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 /** the concatenation of all the bytes of all handshake messages sent or recieved */
147 public byte[] handshakes = new byte[] { };
149 /** true iff we're using SSL_RSA_EXPORT_WITH_RC4_40_MD5 */
150 boolean export = false;
152 public InputStream getInputStream() throws IOException { return is != null ? is : super.getInputStream(); }
153 public OutputStream getOutputStream() throws IOException { return os != null ? os : super.getOutputStream(); }
155 public TinySSL(String host, int port) throws IOException { this(host, port, true); }
156 public TinySSL(String host, int port, boolean negotiateImmediately) throws IOException {
159 if (negotiateImmediately) negotiate();
162 /** negotiates the SSL connection */
163 public void negotiate() throws IOException {
164 os = new SSLOutputStream(super.getOutputStream());
165 is = new SSLInputStream(super.getInputStream());
166 os.writeClientHello();
167 is.readServerHandshakes();
168 os.sendClientHandshakes();
169 is.readServerFinished();
172 class SSLInputStream extends InputStream {
174 /** the underlying inputstream */
177 /** the server's sequence number */
178 public int seq_num = 0;
180 /** the decryption engine */
181 public RC4Engine rc4 = null;
183 /** pending bytes -- decrypted, but not yet fed to consumer */
188 public void mark() { }
189 public void reset() { }
190 public boolean markSupported() { return false; }
191 public long skip(long l) throws IOException { for(long i=0; i<l; i++) read(); return l; }
192 public SSLInputStream(InputStream raw) { this.raw = new DataInputStream(raw); }
193 public int available() throws IOException { return pendlen; }
195 public int read() throws IOException {
196 byte[] singlebyte = new byte[1];
197 int numread = read(singlebyte);
198 if (numread != 1) return -1;
199 return (int)singlebyte[0];
202 public int read(byte[] b, int off, int len) throws IOException {
205 if (pend == null) return -1;
207 pendlen = pend.length;
209 int ret = Math.min(len, pendlen);
210 System.arraycopy(pend, pendstart, b, off, ret);
216 /** reads and decrypts exactly one record; blocks if unavailable */
217 public byte[] readRecord() throws IOException {
219 // we only catch EOFException here, because anywhere else
220 // would be "unusual", and we *want* and EOFException in
223 try { type = raw.readByte();
224 } catch (EOFException e) {
225 if (Log.on) Log.log(this, "got EOFException reading packet type");
229 byte ver_major = raw.readByte();
230 byte ver_minor = raw.readByte();
231 short len = raw.readShort();
232 if (Log.on) Log.log(this, "got record of type " + type + ", SSLv" + ver_major + "." + ver_minor + ", length=" + len);
234 byte[] ret = new byte[len];
237 // simply ignore ChangeCipherSpec messages -- we change as soon as we send ours
239 if (Log.on) Log.log(this, "got ChangeCipherSpec; ignoring");
244 byte[] decrypted_payload;
246 // if crypto hasn't been enabled yet; skip crypt and hash
247 if (rc4 == null) decrypted_payload = ret;
249 // decrypt the payload
250 decrypted_payload = new byte[len - 16];
251 rc4.processBytes(ret, 0, len - 16, decrypted_payload, 0);
254 byte[] MAC = new byte[16];
255 rc4.processBytes(ret, len - 16, 16, MAC, 0);
256 byte[] ourMAC = computeMAC(type, decrypted_payload, 0, decrypted_payload.length, server_write_MAC_secret, seq_num++);
257 for(int i=0; i<MAC.length; i++)
258 if (MAC[i] != ourMAC[i])
259 throw new SSLException("MAC mismatch on byte " + i + ": got " + MAC[i] + ", expecting " + ourMAC[i]);
263 if (decrypted_payload[1] > 1) {
264 throw new SSLException("got SSL ALERT message, level=" + decrypted_payload[0] + " code=" + decrypted_payload[1]);
265 } else if (decrypted_payload[1] == 0) {
266 if (Log.on) Log.log(this, "server requested connection closure; returning null");
269 if (Log.on) Log.log(this, "got SSL ALERT message, level=" + decrypted_payload[0] + " code=" + decrypted_payload[1]);
273 } else if (type == 22) {
274 if (Log.on) Log.log(this, "read a handshake");
276 } else if (type != 23) {
277 if (Log.on) Log.log(this, "unexpected record type: " + type + "; skipping");
282 if (Log.on) Log.log(this, " returning " + decrypted_payload.length + " byte record payload");
283 return decrypted_payload;
286 private byte[] readHandshake() throws IOException {
287 // acquire a handshake message
288 byte type = (byte)read();
289 int len = ((read() & 0xff) << 16) | ((read() & 0xff) << 8) | (read() & 0xff);
290 byte[] rec = new byte[len + 4];
292 rec[1] = (byte)(((len & 0x00ff0000) >> 16) & 0xff);
293 rec[2] = (byte)(((len & 0x0000ff00) >> 8) & 0xff);
294 rec[3] = (byte)((len & 0x000000ff) & 0xff);
295 if (len > 0) read(rec, 4, len);
299 /** This reads the ServerHello, Certificate, and ServerHelloDone handshake messages */
300 public void readServerHandshakes() throws IOException {
303 byte[] rec = readHandshake();
304 handshakes = concat(new byte[][] { handshakes, rec });
305 DataInputStream stream = new DataInputStream(new ByteArrayInputStream(rec, 4, rec.length - 4));
308 case 2: // ServerHello
309 if (Log.on) Log.log(this, "got ServerHello");
310 byte ver_major = rec[4];
311 byte ver_minor = rec[5];
312 System.arraycopy(rec, 6, server_random, 0, server_random.length);
313 short cipher_high = rec[6 + server_random.length + rec[6 + server_random.length] + 1];
314 short cipher_low = rec[6 + server_random.length + rec[6 + server_random.length] + 2];
316 if (cipher_low == 0x04 || cipher_high != 0x00) {
318 if (Log.on) Log.log(this, "using SSL_RSA_WITH_RC4_128_MD5");
320 } else if (cipher_low == 0x03 || cipher_high != 0x00) {
322 if (Log.on) Log.log(this, "using SSL_RSA_EXPORT_WITH_RC4_40_MD5");
324 } else throw new SSLException("server asked for cipher " + ((cipher_high << 8) | cipher_low) +
325 " but we only do SSL_RSA_WITH_RC4_128_MD5 (0x0004) and " +
326 "SSL_RSA_EXPORT_WITH_RC4_40_MD5 (0x0003)");
328 byte compressionMethod = rec[6 + server_random.length + rec[6 + server_random.length] + 3];
329 if (compressionMethod != 0x0) throw new SSLException("server asked for compression method " + compressionMethod +
330 " but we don't support compression");
333 case 11: // Server's certificate(s)
334 if (Log.on) Log.log(this, "got Server Certificate(s)");
335 int numcertbytes = ((rec[4] & 0xff) << 16) | ((rec[5] & 0xff) << 8) | (rec[6] & 0xff);
337 X509CertificateStructure last_cert = null;
338 X509CertificateStructure this_cert = null;
340 for(int i=0; i<numcertbytes;) {
341 int certlen = ((rec[7 + i] & 0xff) << 16) | ((rec[7 + i + 1] & 0xff) << 8) | (rec[7 + i + 2] & 0xff);
343 DERInputStream dIn = new DERInputStream(new ByteArrayInputStream(rec, 7 + i + 3, certlen));
344 this_cert = new X509CertificateStructure((DERConstructedSequence)dIn.readObject());
345 } catch (Exception e) {
346 SSLException t = new SSLException("error decoding server certificate: " + e);
347 t.fillInStackTrace();
351 if (server_cert == null) {
352 server_cert = this_cert;
353 TBSCertificateStructure tbs = server_cert.getTBSCertificate();
354 X509Name subject = tbs.getSubject();
356 // gross hack to extract the Common Name so we can compare it to the server hostname
357 String CN = tbs.getSubject().toString() + " ";
358 boolean good = false;
359 for(int j=0; j<CN.length() - 3; j++)
360 if (CN.substring(j, j+3).equals("CN=")) {
362 CN = CN.substring(j+3, CN.indexOf(' ', j+3));
366 if (!good) throw new SSLException("server certificate does not seem to have a CN: " + CN);
367 if (!CN.equals(hostname))
368 throw new SSLException("connecting to host " + hostname + " but server certificate was issued for " + CN);
370 SimpleDateFormat dateF = new SimpleDateFormat("MM-dd-yy-HH-mm-ss-z");
372 // the following idiocy is a result of the brokenness of the GNU Classpath's SimpleDateFormat
373 String s = tbs.getStartDate().getTime();
374 s = s.substring(2, 4) + "-" + s.substring(4, 6) + "-" + s.substring(0, 2) + "-" + s.substring(6, 8) + "-" +
375 s.substring(8, 10) + "-" + s.substring(10, 12) + "-" + s.substring(12);
376 Date startDate = dateF.parse(s, new ParsePosition(0));
378 s = tbs.getEndDate().getTime();
379 s = s.substring(2, 4) + "-" + s.substring(4, 6) + "-" + s.substring(0, 2) + "-" + s.substring(6, 8) + "-" +
380 s.substring(8, 10) + "-" + s.substring(10, 12) + "-" + s.substring(12);
381 Date endDate = dateF.parse(s, new ParsePosition(0));
383 Date now = new Date();
384 if (now.after(endDate)) throw new SSLException("server certificate expired on " + endDate);
385 if (now.before(startDate)) throw new SSLException("server certificate will not be valid until " + startDate);
387 Log.log(this, "server cert (name, validity dates) checks out okay");
389 } else if (!isSignedBy(last_cert, this_cert.getSubjectPublicKeyInfo()))
390 throw new SSLException("the server sent a broken chain of certificates");
392 last_cert = this_cert;
396 if (Log.on) Log.log(this, " Certificate (" + numcerts + " certificates)");
398 boolean good = false;
400 // pass 1 -- only check CA's whose subject is a partial match
401 String subject = this_cert.getSubject().toString();
402 for(int i=0; i<trusted_CA_public_keys.length; i++) {
403 if (subject.indexOf(trusted_CA_public_key_identifiers[i]) != -1 && isSignedBy(this_cert, trusted_CA_public_keys[i])) {
404 if (Log.on) Log.log(this, "pass 1: server cert was signed by trusted CA " + i);
410 // pass 2 -- try all certs
412 for(int i=0; i<trusted_CA_public_keys.length; i++) {
413 if (isSignedBy(this_cert, trusted_CA_public_keys[i])) {
414 if (Log.on) Log.log(this, "pass 2: server cert was signed by trusted CA " + i);
420 if (!good) throw new SSLException("server cert was not signed by a trusted CA");
424 if (Log.on) Log.log(this, "got ServerKeyExchange");
425 serverKeyExchange = rec;
429 if (Log.on) Log.log(this, "got Request for Client Certificates");
430 cert_requested = true;
433 case 14: if (Log.on) Log.log(this, " ServerHelloDone"); return;
434 default: throw new SSLException("unknown handshake of type " + rec[0]);
439 public void readServerFinished() throws IOException {
441 byte[] rec = readHandshake();
442 if (rec[0] != 20) throw new SSLException("expecting server Finished message, but got message of type " + rec[0]);
444 byte[] expectedFinished = concat(new byte[][] {
445 md5(new byte[][] { master_secret, pad2,
446 md5(new byte[][] { handshakes, new byte[] { (byte)0x53, (byte)0x52, (byte)0x56, (byte)0x52 },
447 master_secret, pad1 }) }),
448 sha(new byte[][] { master_secret, pad2_sha,
449 sha(new byte[][] { handshakes, new byte[] { (byte)0x53, (byte)0x52, (byte)0x56, (byte)0x52 },
450 master_secret, pad1_sha } ) } ) } );
452 for(int i=0; i<expectedFinished.length; i++)
453 if (expectedFinished[i] != rec[i + 4])
454 throw new SSLException("server Finished message mismatch!");
456 if (Log.on) Log.log(this, "server finished message checked out okay!");
461 class SSLOutputStream extends OutputStream {
463 /** the underlying outputstream */
464 DataOutputStream raw;
466 /** the sequence number for sending */
467 public long seq_num = 0;
469 /** the encryption engine for sending */
470 RC4Engine rc4 = null;
472 public SSLOutputStream(OutputStream raw) { this.raw = new DataOutputStream(raw); }
473 public void flush() throws IOException { raw.flush(); }
474 public void write(int b) throws IOException { write(new byte[] { (byte)b }, 0, 1); }
475 public void write(byte[] b, int off, int len) throws IOException { write(b, off, len, (byte)23); }
476 public void close() throws IOException {
477 write(new byte[] { 0x1, 0x0 }, 0, 2, (byte)21);
481 /** writes a single SSL Record */
482 public void write(byte[] payload, int off, int len, byte type) throws IOException {
484 // largest permissible frame is 2^14 octets
486 write(payload, off, 1 << 14, type);
487 write(payload, off + 1 << 14, len - 1 << 14, type);
492 raw.writeShort(0x0300);
496 raw.write(payload, off, len);
499 byte[] MAC = computeMAC(type, payload, off, len, client_write_MAC_secret, seq_num);
500 byte[] encryptedPayload = new byte[MAC.length + len];
501 rc4.processBytes(payload, off, len, encryptedPayload, 0);
502 rc4.processBytes(MAC, 0, MAC.length, encryptedPayload, len);
503 raw.writeShort(encryptedPayload.length);
504 raw.write(encryptedPayload);
511 /** tacks a handshake header onto payload before sending it */
512 public void writeHandshake(int type, byte[] payload) throws IOException {
513 byte[] real_payload = new byte[payload.length + 4];
514 System.arraycopy(payload, 0, real_payload, 4, payload.length);
515 real_payload[0] = (byte)(type & 0xFF);
516 intToBytes(payload.length, real_payload, 1, 3);
517 handshakes = concat(new byte[][] { handshakes, real_payload });
518 write(real_payload, 0, real_payload.length, (byte)22);
521 public void sendClientHandshakes() throws IOException {
523 if (Log.on) Log.log(this, "shaking hands");
524 if (cert_requested) {
525 if (Log.on) Log.log(this, "telling the server we have no certificates");
526 writeHandshake(11, new byte[] { 0x0, 0x0, 0x0 });
529 // generate the premaster secret
530 byte[] pre_master_secret = new byte[48];
531 pre_master_secret[0] = 0x03; // first two bytes of premaster secret are our version number
532 pre_master_secret[1] = 0x00;
533 getRandomBytes(pre_master_secret, 2, pre_master_secret.length - 2);
535 // encrypt and send the pre_master_secret
537 byte[] encrypted_pre_master_secret;
539 SubjectPublicKeyInfo pki = server_cert.getSubjectPublicKeyInfo();
540 RSAPublicKeyStructure rsa_pks = new RSAPublicKeyStructure((DERConstructedSequence)pki.getPublicKey());
541 BigInteger modulus = rsa_pks.getModulus();
542 BigInteger exponent = rsa_pks.getPublicExponent();
544 if (serverKeyExchange != null) {
546 AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine());
547 rsa.init(false, new RSAKeyParameters(false, modulus, exponent));
549 int modulus_size = ((serverKeyExchange[4] & 0xff) << 8) | (serverKeyExchange[5] & 0xff);
550 byte[] b_modulus = new byte[modulus_size];
551 System.arraycopy(serverKeyExchange, 6, b_modulus, 0, modulus_size);
552 modulus = new BigInteger(1, b_modulus);
554 int exponent_size = ((serverKeyExchange[6 + modulus_size] & 0xff) << 8) | (serverKeyExchange[7 + modulus_size] & 0xff);
555 byte[] b_exponent = new byte[exponent_size];
556 System.arraycopy(serverKeyExchange, 8 + modulus_size, b_exponent, 0, exponent_size);
557 exponent = new BigInteger(1, b_exponent);
559 byte[] server_params = new byte[modulus_size + exponent_size + 4];
560 System.arraycopy(serverKeyExchange, 4, server_params, 0, server_params.length);
562 byte[] expectedSignature = concat(new byte[][] { md5(new byte[][] { client_random, server_random, server_params } ),
563 sha(new byte[][] { client_random, server_random, server_params } ) } );
565 byte[] recievedSignature = rsa.processBlock(serverKeyExchange, 6 + server_params.length,
566 serverKeyExchange.length - 6 - server_params.length);
568 for(int i=0; i<expectedSignature.length; i++)
569 if (expectedSignature[i] != recievedSignature[i])
570 throw new SSLException("ServerKeyExchange message had invalid signature " + i);
572 if (Log.on) Log.log(this, "ServerKeyExchange successfully processed");
575 AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine());
576 rsa.init(true, new RSAKeyParameters(false, modulus, exponent));
578 encrypted_pre_master_secret = rsa.processBlock(pre_master_secret, 0, pre_master_secret.length);
579 writeHandshake(16, encrypted_pre_master_secret);
581 } catch (Exception e) {
582 SSLException t = new SSLException("exception encrypting premaster secret");
583 t.fillInStackTrace();
588 if (Log.on) Log.log(this, "Handshake complete; sending ChangeCipherSpec");
589 write(new byte[] { 0x01 }, 0, 1, (byte)20);
592 // compute master_secret
593 master_secret = concat(new byte[][] {
594 md5(new byte[][] { pre_master_secret,
595 sha(new byte[][] { new byte[] { 0x41 }, pre_master_secret, client_random, server_random })}),
596 md5(new byte[][] { pre_master_secret,
597 sha(new byte[][] { new byte[] { 0x42, 0x42 }, pre_master_secret, client_random, server_random })}),
598 md5(new byte[][] { pre_master_secret,
599 sha(new byte[][] { new byte[] { 0x43, 0x43, 0x43 }, pre_master_secret, client_random, server_random })})
602 // construct the key material
603 byte[] key_material = new byte[] { };
604 for(int i=0; key_material.length < 72; i++) {
605 byte[] crap = new byte[i + 1];
606 for(int j=0; j<crap.length; j++) crap[j] = (byte)(((byte)0x41) + ((byte)i));
607 key_material = concat(new byte[][] { key_material,
608 md5(new byte[][] { master_secret,
609 sha(new byte[][] { crap, master_secret, server_random, client_random }) }) });
612 client_write_key = new byte[export ? 5 : 16];
613 server_write_key = new byte[export ? 5 : 16];
615 System.arraycopy(key_material, 0, client_write_MAC_secret, 0, 16);
616 System.arraycopy(key_material, 16, server_write_MAC_secret, 0, 16);
617 System.arraycopy(key_material, 32, client_write_key, 0, export ? 5 : 16);
618 System.arraycopy(key_material, export ? 37 : 48, server_write_key, 0, export ? 5 : 16);
621 // see SSLv3 spec, 6.2.2 for explanation
622 byte[] client_untrimmed = md5(new byte[][] { concat(new byte[][] { client_write_key, client_random, server_random } ) });
623 byte[] server_untrimmed = md5(new byte[][] { concat(new byte[][] { server_write_key, server_random, client_random } ) });
624 client_write_key = new byte[16];
625 server_write_key = new byte[16];
626 System.arraycopy(client_untrimmed, 0, client_write_key, 0, 16);
627 System.arraycopy(server_untrimmed, 0, server_write_key, 0, 16);
630 rc4 = new RC4Engine();
631 rc4.init(true, new KeyParameter(client_write_key));
632 is.rc4 = new RC4Engine();
633 is.rc4.init(false, new KeyParameter(server_write_key));
636 writeHandshake(20, concat(new byte[][] {
637 md5(new byte[][] { master_secret, pad2,
638 md5(new byte[][] { handshakes, new byte[] { (byte)0x43, (byte)0x4C, (byte)0x4E, (byte)0x54 },
639 master_secret, pad1 }) }),
640 sha(new byte[][] { master_secret, pad2_sha,
641 sha(new byte[][] { handshakes, new byte[] { (byte)0x43, (byte)0x4C, (byte)0x4E, (byte)0x54 },
642 master_secret, pad1_sha } ) })
645 if (Log.on) Log.log(this, "wrote Finished message");
649 public void writeClientHello() throws IOException {
651 if (Log.on) Log.log(this, "sending ClientHello");
652 int unixtime = (int)(System.currentTimeMillis() / (long)1000);
654 byte[] out = new byte[] {
655 0x03, 0x00, // client version (SSLv3.0)
657 // space for random bytes
658 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
659 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
662 0x0, // empty vector for sessionid
663 0x0, 0x4, 0x0, 0x4, 0x0, 0x3, // we support two ciphersuites: SSL_RSA_WITH_RC4_128_MD5 and SSL_RSA_EXPORT_WITH_RC4_40_MD5
664 0x1, 0x0 // we only support one compression method: none
667 // don't need to use secure random here since it's sent in the clear
668 Random rand = new Random(System.currentTimeMillis());
669 rand.nextBytes(client_random);
670 intToBytes(unixtime, client_random, 0, 4);
671 System.arraycopy(client_random, 0, out, 2, client_random.length);
673 writeHandshake(1, out);
678 // Static Helpers ////////////////////////////////////////////////////////////////////
680 /** copy the least significant num bytes of val into byte array b, startint at offset */
681 public static void intToBytes(long val, byte[] b, int offset, int num) {
682 for(int i=0; i<num; i++)
683 b[offset + num - i - 1] = (byte)((val & (0xFFL << (i * 8))) >> (i * 8));
686 /** fills b with random bytes */
687 public static synchronized void getRandomBytes(byte[] b, int offset, int len) {
688 MD5Digest md5 = new MD5Digest();
689 byte[] b2 = new byte[16];
692 md5.update(randpool, 0, randpool.length);
693 intToBytes(randcnt++, b2, 0, 8);
694 md5.update(b2, 0, 8);
696 int n = len < 16 ? len : 16;
697 System.arraycopy(b2, 0, b, offset, n);
703 public static byte[] computeMAC(byte type, byte[] payload, int off, int len, byte[] MAC_secret, long seq_num) {
704 byte[] MAC = new byte[16];
705 MD5Digest md5 = new MD5Digest();
706 md5.update(MAC_secret, 0, MAC_secret.length);
707 md5.update(pad1, 0, pad1.length);
709 byte[] b = new byte[11];
710 intToBytes(seq_num, b, 0, 8);
712 intToBytes(len, b, 9, 2);
713 md5.update(b, 0, b.length);
715 md5.update(payload, off, len);
718 md5.update(MAC_secret, 0, MAC_secret.length);
719 md5.update(pad2, 0, pad2.length);
720 md5.update(MAC, 0, MAC.length);
726 public static byte[] concat(byte[][] inputs) {
728 for(int i=0; i<inputs.length; i++) total += inputs[i].length;
729 byte[] ret = new byte[total];
731 for(int i=0; i<inputs.length; i++) {
732 System.arraycopy(inputs[i], 0, ret, pos, inputs[i].length);
733 pos += inputs[i].length;
738 SHA1Digest master_sha1 = new SHA1Digest();
739 public byte[] sha(byte[][] inputs) {
741 for(int i=0; i<inputs.length; i++) master_sha1.update(inputs[i], 0, inputs[i].length);
742 byte[] ret = new byte[master_sha1.getDigestSize()];
743 master_sha1.doFinal(ret, 0);
747 MD5Digest master_md5 = new MD5Digest();
748 public byte[] md5(byte[][] inputs) {
750 for(int i=0; i<inputs.length; i++) master_md5.update(inputs[i], 0, inputs[i].length);
751 byte[] ret = new byte[master_md5.getDigestSize()];
752 master_md5.doFinal(ret, 0);
756 // FEATURE: improve error reporting in here
757 /** returns true iff certificate "signee" is signed by public key "signer" */
758 public static boolean isSignedBy(X509CertificateStructure signee, SubjectPublicKeyInfo signer) throws SSLException {
762 String signature_algorithm_oid = signee.getSignatureAlgorithm().getObjectId().getId();
763 if (signature_algorithm_oid.equals("1.2.840.113549.1.1.4")) hash = new MD5Digest();
764 else if (signature_algorithm_oid.equals("1.2.840.113549.1.1.2")) hash = new MD2Digest();
765 else if (signature_algorithm_oid.equals("1.2.840.113549.1.1.5")) hash = new SHA1Digest();
766 else throw new SSLException("unsupported signing algorithm: " + signature_algorithm_oid);
769 // decrypt the signature using the signer's public key
770 byte[] ED = signee.getSignature().getBytes();
771 SubjectPublicKeyInfo pki = signer;
772 RSAPublicKeyStructure rsa_pks = new RSAPublicKeyStructure((DERConstructedSequence)pki.getPublicKey());
773 BigInteger modulus = rsa_pks.getModulus();
774 BigInteger exponent = rsa_pks.getPublicExponent();
775 AsymmetricBlockCipher rsa = new PKCS1(new RSAEngine());
776 rsa.init(false, new RSAKeyParameters(false, modulus, exponent));
778 // Decode the embedded octet string
779 byte[] D = rsa.processBlock(ED, 0, ED.length);
780 BERInputStream beris = new BERInputStream(new ByteArrayInputStream(D));
781 DERObject derob = beris.readObject();
782 DERConstructedSequence dercs = (DERConstructedSequence)derob;
783 DEROctetString deros = (DEROctetString)dercs.getObjectAt(1);
784 byte[] MD = deros.getOctets();
786 // generate our own hash
787 ByteArrayOutputStream baos = new ByteArrayOutputStream();
788 DEROutputStream dos = new DEROutputStream(baos);
789 dos.writeObject(signee.getTBSCertificate());
791 byte[] b = baos.toByteArray();
792 hash.update(b, 0, b.length);
793 byte[] md_out = new byte[MD.length];
794 hash.doFinal(md_out, 0);
796 // compare our hash to the signed hash
797 for(int j=0; j<MD.length; j++) if (md_out[j] != MD[j]) return false;
800 } catch (Exception e) {
806 // Embedded Trusted Public Keys //////////////////////////////////////////////
808 /** base64-encoded sequence of DER-encoded PKCS7 certs for all the "trusted root CA's" included with IE5.5 */
809 static String[] base64_encoded_trusted_CA_public_keys = new String[] {
811 "CN=ABA.ECOM Root CA",
812 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdMR4HlVQwcITMsFQgDiDYNGPe" +
813 "STurYG0w1ZvT7BzkNnAYohqO+8zNCizLBVllOEZgUA2kRJgNhUCqUlhpTtY1b/cGyjoRnS" +
814 "eL5oKkReL8/MGF5HvDqxRj0e8LksNF+MfEwIKZ1AVes8fYPetfD3ioMOoUy0OqWzX1oil+" +
815 "wZm8EFaP3mt6mRlCzkeEgkGiUZOuuVnDkKis9CsvAc1V/7a+1oVns5LHI4sO6TqdN7dzzr" +
816 "cQOpOEoWbIkqytozE3nCVYztnLvyy1sQ+C5hNcYpTCrQKmPRZVm0+M359ACEtldChZ0yqP" +
817 "kqVPv/eEG8vXEo9LuQvP+WNATjRZ6hRihAgQIDAQAB",
820 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCws2enlrV2g+kWA9kaoHbVdOecBdJRP9" +
821 "tPGaGoOU7LJH1hxB5qIK4Pgd7quDn9Gx9rNkDtTSEl8qPZoVHYbMAblvjUQpTUp84bj9NU" +
822 "JqKE7zKFr0o/8TI2rz3mOifrA8IlfvRhK62KGkvmmzZo1C/l0oiU3Baq2sIVTGzD4RmRyQ" +
825 "CN=Xcert EZ by DST",
826 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArVQY3rS/963odKrti3yPwtR1Gt" +
827 "WEubZi/Inv5JdhkvsduOFaRzSengYi+9PqOMu4iwf3GqAXdwdaMBzUKTgg1ydA2FCTQ7/S" +
828 "GKIpdgVyqmu2aZireR4cZfVqi/zFFqqictpg7U5uGSV6Ch0w41CbQjxE66GwIB7bAn7+PR" +
829 "+/0ACK20B2philFadXtlLCAReYd4+KgcYatGoq5q+p1gCsz9gVSXzbG6H+gfqH+dOQwQLA" +
830 "+dBC6ZFoJV/Gv4c56ZUAYCi/gyzA51621zYW52CHdujnJ7IlDYt65aod5VnNzgsOb8bInO" +
831 "MQ2YU507eb+sa6fHTSXXVWq3SkolG/UnzucQIDAQAB",
833 "CN=Certiposte Classe A Personne",
834 "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQAox3xaJSN48rMAR0Biy2+MQlCfnl" +
835 "7UXA5lC1hWlSvjRtBhNuAtRpuCy5Hu0pV8mpKvBAp+pp/g17HDRfmYQRs5redW19m2f867" +
836 "OS4sO8+2cwODzhNdMmpjottb+Esz6FBsy6gX7J6TuWwGSyYLdx6e+eWMiTfS0bv9qYwrLJ" +
837 "wQMdhLjM23cX44LCnjF7JP6FK245I80v3hAtphEHTSGvPI0dFmB1/EhGNpva5s3GUjHLf7" +
838 "98YTLoN+P6nlCyBtAQo34lzait4icOkN4HQ9xOtxm2Eq4g0Ui0xGN0wm0mjWVsNXqqJgN6" +
839 "9fnaCzgILmQypMgAAJUNmoanNtA/5ec5LlAgMBAAE=",
841 "CN=Certiposte Serveur",
842 "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQA+p3gzOJHiylaV0ZFGsiPcpVZ/D8" +
843 "eXuOKekS4oFi6O80e2XIPE8Ob+ZxqTZH1ACdgdaADs1BHu2GOJAyPphF/HVQ5K4nK7KcFV" +
844 "ZHao45LN9/ZuQlYYUjOJ+YAUqBlRfsd3v3qoMcB9F25DTtVmyQU+S+Ll4lUbdKpRHarMmB" +
845 "F3pOvbKg4nx9XNSOzcfk5J50HNmQvRS14YGw06CpstmznHQAzQdgd8fI9+XHKOh9W+8qa5" +
846 "3r/dnxJ5R3zFyZdARgCS0xNak0+dfthfTMFdSEnZLZg8/MynhyHwPo5yfVk4NhYaDEi+of" +
847 "LVPqgWDCBZz84PM4M9rav1/93X/WkIiADvAgMBAAE=",
849 "OU=Certisign - Autoridade Certificadora - AC2",
850 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5MMyl65DWVpRnM4mDbUa+cJeTF04KJ3" +
851 "DOycXyxdIt0RGcdzJsdNOSb/rp1bhhmqpMEz41OvDuCTbZ0Zcxx16sQUm/SG1OIFPJe2qj" +
852 "ljFrsm6ozy9yTAatMs9aCPN9EJyqu7pz+fPwuCRvqGW2Iv4FWxBVRMIDHa3RIswIbfuMyw" +
855 "OU=Certisign - Autoridade Certificadora - AC4",
856 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDsg9TMg5A/X+y+wenQx1hGWR/xk0qyFx" +
857 "MLzymZqwRFM+PRXr68jiV3Yt2bkpsxCkBFedXys91suUD9mH9Aoi3pspO9S9XB3unR+nH3" +
858 "P0G89BSvzWvIOUqdYGW0hNBqQeljrptp6rlGHNsYCDtiTN5B156GfxNyEdTc6t5gpbvdGw" +
861 "OU=Certisign Autoridade Certificadora AC1S",
862 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwwJXro8VB+JtvcWOOkRFX+QPHaJoanG" +
863 "Hwww8Ml2KIfiYBNX398W9PF5WqfvK7vO/idnNhlTZRgz6E6D+6VzY3lBNskmQflA3rVC9R" +
864 "WuUoXvCShufkbSF6XzcL51u9LQKogfk/yxTIvKTF49HLN9yr5Yeq8guYLnrPzB7Cf+j9AQ" +
867 "OU=Certisign Autoridade Certificadora AC3S",
868 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOZE7Wz658mCeY7yjvujTDNRqd0mYecf" +
869 "Hkli0nFzmQRY8t7+bVR6nhg4F8Pihx+oC7XfhDaxkQwZhvFZ4trklkROyEGmlZFleyPZLY" +
870 "Zku/ma1DGMc4yYuOLAQus0trk/adH4SyzeYAwr42pbxZtZ+LGSD/5agopFW2irayxddE4w" +
873 "O=Certplus, CN=Class 1 Primary CA",
874 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw2spyC7HrnxSBemTiVYKWnnJzN" +
875 "wl74eKLQXYgRcEGzpF+HkODUnUgUHIq0X7dcgV8uLQvNlhbISkExmn2fnySdxMD8Z9V7QT" +
876 "3B4JcSk2nYBY9BvYiRTr09KTSyrxd+dqZb0Z5ar9DEpj4cKZtA8EtlobNjw3PL/F5V7xX1" +
877 "cOH8f9LOfkb2qbYpY5EZtm8Cy2UtzhJ//bbf7rq2MUHWOIY+IWDPkgVA+b3RVqdoNPvSeL" +
878 "U6Y30ofyR1BSO2bp0XgaG7I7afBZPDhb0SpMM14Oylal7S1bgoNN1jhOila2ai8kaxIwpi" +
879 "rerwy7qkQSHBPFZQ/j/dgaMUvkPwx8RegWMwIDAQAB",
881 "O=Certplus, CN=Class 2 Primary CA",
882 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3FCW0BL4NdIIeHq2UnD9b+7PuR" +
883 "HLXXfh7Ol+BI3WzG9zQ1dgrDMKROwDXxyAJJHlqJFWEoL34Cv0265hLokQjWtsurMCvdU2" +
884 "xUg3I+LwWjdSMxcS4tFgTb4vQRHj9hclDIuRwBuZe5lWDa/u0rxHV+N5SXs0iSckhN6x7O" +
885 "lYTv5O31q+Qa2sCMUYDu/SU+5s0J0SARON3IBi95WpRIhKcU5gVZ7bIxl5VgcMP2MLXLDi" +
886 "vn4V/JQzWEE4dMThj4vfJqwftYs7t0NZa7Akpm2Qi8Ry6l0zmLfL3l5775TxGz7KySHBxZ" +
887 "gCqqL2W3eb9X6WVTQcZ2nA8ULjR6z8KBxmVQIDAQAB",
889 "O=Certplus, CN=Class 3 Primary CA",
890 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt5QwbtBM2X5eYOVvuybKUm9rbI" +
891 "WZpQvvABpvG01YtRgH+t17+MssUt38nLiNUum5sgt89Y9bmUgJWN7NSJWGJYkFNCcwC1e2" +
892 "DHdjKctsqj65mVESDZhwdkdM+UmWIgj5a+qqADajFaccHp+Mylp5eyHaiR9jfnmSUAkEKK" +
893 "3O420ESUqZsT9FCXhYIO+N/oDIBO0pLKBYjYQCJZc/oBPXe4sj45+4x7hCQDgbkkq9SpRV" +
894 "x1YVDYF3zJ+iN4krW4UNi3f4xIv7EMuUx+kaVhKXZhTEu9d9bQIbv3FiJhjpSYr6o97hhK" +
895 "2AykriIoxqCGGDsiLHCYg4Vl3RMavwCZ8TWQIDAQAB",
897 "CN=Autoridad Certificadora de la Asociacion Nacional del Notariado Mexicano",
898 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7tlrVYRxJvaOrUG71tLeY+ryP2" +
899 "XyOxPBrlEm9L94j8ZMSay/Qd71KMco55/XgOXU7iMrk5U9yY9q9coA6RDHiIIabqNf8DRS" +
900 "ISVoKPiV8ICVoiyxP2r2KNbihP0WZ5wluXXb5cZZA7SrQgeI1VxIRaIJA8muZ5KoolPHyq" +
901 "t+mhKVWgVXjRBklicRsOYyMFvNPQygGxMtuxqr3TnOkmuiBNQTX213Z1Q5qHtpisZfeMoH" +
902 "GGlu+cDT0IqOrx4waO742KhmDIR9I2qJPGJNFHSs25uc/LCD/gcw8factEjI5jpCJQko91" +
903 "bCsdejmHcCh+qKwV3axIonB4VeSExVKEDtCQIDAQAB",
905 "O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
906 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhA" +
907 "wL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lw" +
908 "dd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpw" +
911 "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
912 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhA" +
913 "wL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lw" +
914 "dd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpw" +
917 "C=FR, O=Certplus, CN=Class 3P Primary CA",
918 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqzf/62CbQXhp9UlYsN4fcWmmK+" +
919 "OuUMapvJPpIL7kxBOCVu/wQzIJypt1A498T+HgT3aeC61kehQ6mp2/LxYLZRyp7py84xpl" +
920 "y0+F6pJWdWbWVUDv+8zWOD+rHO9CjRmJ9reVhsKnHen3KfEq2WV5/Cv1jsoad36e6Kz5Zr" +
921 "9F++gTnV+2c+V9e477EnRdHwZehRumXhhEALq8027RUg4GrevutbTBu7zrOA9IIpHHb9K4" +
922 "cju6f8CNbLe8R3MhKoX/rNYoohnVl2o6uaxtRezmTcPbqF3FXYKYrEpaquYrCAwQdLxi9j" +
923 "pJBGbYURwmpth1n5y/rmBRPVy8ok97iWfNUwIDAQAB",
925 "C=FR, O=Certplus, CN=Class 3TS Primary CA",
926 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvWWaI0MAPPklAUOYW0Y0N2c39F" +
927 "tXjqPezYwvQbMVPeWYi/LMXKfHrzXHs6dPxxApV+kDiYNyBnZSwXACN0Dt8M6LsbGJrAKo" +
928 "W93c1UNFBtwotulRG2ru83tIxZ0Rro2mcpPAJUKRqD5G4mhMgUCwQtN6vntH0kdQDKQSps" +
929 "rkEtDAfDo8AanKApbeglrF+xm6PJzYD3QfmBiulFAyB1IQEUpL7FhVLNSeS5R7BdJy3wbw" +
930 "jcsInuTutEStgvEbYWrxs/gWMTZCJLqQv7V+YW7CWQxUebRMiCgezBvfhIsjyL6vB/KRst" +
931 "qNyoxffCg8fIlsBlm9Ps7FgtNqyaxoVe7FrwIDAQAB",
933 "C=US, O=RSA Data Security, Inc., OU=Commercial Certification Authority",
934 "MIGbMA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AKT7gWJ7zhAn3ej3vmxuxnCZ27jVBQNpKI" +
935 "Kccn+WP47srCmSP4oU+EJ2vr1dA7mQ1NC8BrJRM1/Ewr+2i4+ZtmIiYN3b3yCCtMqiLy1Q" +
936 "7ZQy3uBVjdRo4uBM0s0FFi6VZlxhUjgeUaiCocTvJekK5osrjjFm2fjZ/b07adnrAgMBAA" +
939 "C=DE, O=Deutsche Telekom AG, OU=T-TeleSec Trust Center, CN=Deutsche Telekom Root CA 1",
940 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQ3ZsMoBdERA+vIUBzZ1bwPmloEbrZN/" +
941 "KBrsMkrGmhzfymGFVW/4ufMsHb53gsOdtggUGl79PNgI0YPOJSDAuf92Se5aDwuGFi9L/g" +
942 "o9pYK/0VBGu9Op58nfI92OSVw+xOwvFlqwxL7EeCW+LhUHXY9mG0GFztM6BLHoP7T4S8eQ" +
945 "C=DE, O=Deutsche Telekom AG, OU=T-TeleSec Trust Center, CN=Deutsche Telekom Root CA 2",
946 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqwujNeCLKRSxFIWvPBDkOW81XU" +
947 "qu3ephjZVJ9G9koxpgZqSpQCKE2dSl5XiTDmgBrblNXDrO07ioQkDfz6O6gllqkhusHJra" +
948 "CCslJ/lpI0fx4Ossepv1EwLQfjR8wp48AFmr9doM9TI8K6xQ2tbD3oOUyqgMmTIOCEhWW2" +
949 "r72uFYWAFJX3JBPBUGAY5draq4k7TNnuun6GotUjTbOu9cdVHa2/Mx+e5xmDLEVBVEDPmb" +
950 "Ve2t3xgIoKOGiknuUwWPGUzV3lh5m9JqHEKrxdWnz2gPluThYZh2YciRfNY+AOKRUIfhnQ" +
951 "rmrZfSHcY6fcu82gM01Y5bAfVqB7cWtm5KfwIDAQAB",
953 "C=US, O=Digital Signature Trust Co., OU=DST (ANX Network) CA",
954 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC0SBGAWKDVpZkP9jcsRLZu0XzzKmueEb" +
955 "aIIwRccSWeahJ3EW6/aDllqPay9qIYsokVoGe3eowiSGv2hDQftsr3G3LL8ltI04ceInYT" +
956 "BLSsbJZ/5w4IyTJRMC3VgOghZ7rzXggkLAdZnZAa7kbJtaQelrRBkdR/0o04JrBvQ24JfQ" +
959 "OU=National Retail Federation, CN=DST (NRF) RootCA",
960 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2aybd/pQ08zcuUCsuXJqAIcj/A" +
961 "+WIdAmr+TitV/606Z9ITAuzBeCj5h0/Gekpt+Il6JCKfWn2xGT+14jMMKqvCLnQRvl7SXe" +
962 "yD/b3ldFeEBGg7LVGj3fD0Vt1WMCddgvxm6rlZF0Nw3LTQlc0dRbOtrdDshrmdjVOczfhV" +
963 "XEklMCo+H3gMlwo9rcM8R/okcIHDWWH6EDHDCD9MTM/5jDsEZEosC/rdvSgfZMmCynXiTz" +
964 "hspj1bp98JrAStAbWO7sqWfPaQJsIsBgLCzRyCDqyC373Zy7y1FM3OdXBDtUmxGlMnTsdA" +
965 "HzkBVbL3wsk2W5Zme0gYg15Z6RGH+BqEHIywIDAQAB",
967 "OU=United Parcel Service, CN=DST (UPS) RootCA",
968 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7xfsrynm2SsnwNt7JJ9m9ASjwq" +
969 "0KyrDNhCuqN/OAoWDvQo/lXXdfV0JU3SvbYbJxXpN7b1/rJCvnpPLr8XOzC431Wdcy36yQ" +
970 "jk4xuiVNtgym8eWvDOHlb1IDFcHfvn5KpqYYRnA/76dNqNz1dNlhekA8oZQo6sKUiMs3FQ" +
971 "UZPJViuhwt+yiM0ciekjxbEVQ7eNlHO5stSuY+e2vf9PYFzyj2upg2AJ48N4UKnN63pIXF" +
972 "Y/23YhRtFx7MioCFQjIRsCHinXfJgBZBnuvlFIl/t8O8T8Gfh5uW7GP2+ZBWDpWjIwqMZN" +
973 "qbuxx3sExd5sjo9X15LVckP8zjPSyYzxKfFwIDAQAB",
975 "CN=Autoridad Certificadora del Colegio Nacional de Correduria Publica Mexicana",
976 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmO0dhYH7/jd0viOAJ18bQX6856" +
977 "WK2HNdlkjqq1iqfaUdz/4gCtnydQnts9X9+JMqGaleqLEU8tZChkFBXk/FVqeaokJvLihI" +
978 "6i6r2cHZmvClnotdEWeaNzdTYGbxIv93d0fp3dwYRu4u3+LBluDqWN6H65OIaZmwPm52KU" +
979 "Bhwyhmc3+sMXb0OM3WMo9zMhAVNNJ8RND8eQwAnX0P4+P3RPWedEknrRvXMshTrm8qsNe1" +
980 "LRgsbjs6TUzb9Wi1L7AMkPk93HU2msLgv7uWiMJr7hjXTlA/V4tnaKS+AzNdWRI0if52yN" +
981 "kVdgFUZP2s41DvEMjQ7l/sHd9PBZg8tBReAQIDAQAB",
984 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0sYmtuelPcHEaNVQb1PFb0kTCb" +
985 "ivLEiNFGqjF19a+dMudS/YKGLRky/8TdSrh+UIx5nnkj91vesltBXBmxk90kSN13QgbTcC" +
986 "j2mTW4rEGZ30sg78Fmy5sQWSg9GFLGCUPkVVoNmrCCHmYOg7dPKZUFFo0AMtsYC+o9hSsE" +
987 "TNQ0pwjliFleFOLNYtQW/WhOfImETKR9ssJKVpJs9ruCdiw/TJepIj7RNngq5FLkXlfnI/" +
988 "hZ2UYhDmPJGhrXcA4BXs84SAcnqObmCXxyRZEDSDW+GlpGm2VzUceFnG0y86c2fulMoEEw" +
989 "ViBnAjs/R87kXZZAtbSaqkQ84mxEQSbLjdeQIDAQAB",
991 "OU=DSTCA X2, CN=DST RootCA X2",
992 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3HXwjMB1lprAYh8m98ThmurgVn" +
993 "Nbmc0BRKgIttWn2hoEGDmSSnijgcL1d3pQtHD/mqvGx8pug09CmPsmC9rcbdapmVVSZ+ko" +
994 "A5Lc5bAFmg8V+WtZclby+jn8qmjuDx8Qgy/8nfoXlt2C4+ZFfcBLgEQf7SzghP2RXJJUaS" +
995 "XlYmnc5e4AUr0zC611AoWnZFAtxRkZMMAm28nT/S6ZrVm1C03UQa6FSENZ3Leo4qLew4/X" +
996 "uKFipmhQUuTPMaeUhdqfRjIXVuXy62Y9Ev9D25jvd8/LgY00scZQSibR5D5BUK9sriI0Lt" +
997 "VrboO6ebh2ZUjaCSlkYyK5+0d2hYyGRMsJ2wIDAQAB",
999 "C=US, O=Digital Signature Trust Co., OU=DST-Entrust GTI CA",
1000 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC2HfdLjQ8T4xL1Cf4GMg6vTEH1fdRHPS" +
1001 "oK34MF3t595gMW9lE6y0caSq1+xP0dtL50injdC4OOtIQTxPv4bSmuoeEPD0PjtV5gafqD" +
1002 "lPx55tx27dFEK479Erv+F3cXDIntp+9RfcTtOMM7o3r74k2gYLXy/RNl08bsP741nD0i7w" +
1005 "C=US, O=Digital Signature Trust Co., OU=DSTCA E1",
1006 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodG" +
1007 "BmE5gGHKlREmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+Lth" +
1008 "zfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQ" +
1011 "C=US, O=Digital Signature Trust Co., OU=DSTCA E2",
1012 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+S" +
1013 "SmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87e" +
1014 "ZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQ" +
1017 "CN=Entrust.net Certification Authority (2048)",
1018 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvw" +
1019 "tKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtL" +
1020 "A/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj/L24Sc" +
1021 "F2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLPKQP5L6RQstRIzgUy" +
1022 "VYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUiVBcAkCaTvA5JaJ" +
1023 "G/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQAB",
1025 "CN=Entrust.net Client Certification Authority",
1026 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/" +
1027 "Bo6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDe" +
1028 "g7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173iw" +
1031 "CN=Entrust.net Secure Server Certification Authority",
1032 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO" +
1033 "2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc" +
1034 "1lB5gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQw" +
1037 "C=US, O=Equifax, OU=Equifax Secure Certificate Authority",
1038 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBXbFYZwhi7qCaLR8IbZEUaJgKHv7aBG" +
1039 "8ThGIhw9F8zp8F4LgB8E407OKKlQRkrPFrU18Fs8tngL9CAo7+3QEJ7OEAFE/8+/AM3UO6" +
1040 "WyvhH4BwmRVXkxbxD5dqt8JoIxzMTVkwrFEeO68r1u5jRXvF2V9Q0uNQDzqI578U/eDHuQ" +
1043 "C=US, O=Equifax Secure Inc., CN=Equifax Secure eBusiness CA-1",
1044 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOLxm8F7d33pOpX1oNF080GgyY9CLZWd" +
1045 "TEaEbwtDXFhQMgxq9FpSFRRUHrFlg2Mm/iUGJk+f1RnKok2fSdgyqHCiHTEjg0bI0Ablqg" +
1046 "2ULuGiGV+VJMVVrFDzhPRvpt+C411h186+LwsHWAyKkTrL6I7zpuq18qOGICsBJ7/o+mAw" +
1049 "CN=Baltimore EZ by DST",
1050 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvMyzPUN5uEf5FbduJrFMkph57c" +
1051 "Vw8zrp1d0D9Co/YIyW5UcWAvc2svGeJoj1nkJlng+uf+PMsW4h9fGIInTWH7J3BDkyuke1" +
1052 "NcATXQFyowVDzE7aJpqHqGFj9GanwxVG6tHR6jDDu3Fqm8FDhsE5H8ZWYAIb/Ig6oJm7jN" +
1053 "d4YdBeV4+RO4CLbv/JZYEKObuQEyA1SD+l4b8twXGDhSDtIIfLtv4ZjATd7Sld3woSzolW" +
1054 "8h9aGTFYtv1jNurJI96nkZcnZXKZbMd6RMRfvpsfHsqeWBymqiNq4wYbkiTYVyIJUBWQRv" +
1055 "CDXraATBKBPWZvBFU6iGvQ71aHUKC51lUbnQIDAQAB",
1057 "C=US, O=Equifax Secure, OU=Equifax Secure eBusiness CA-2",
1058 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkOTmTHlIGGyg2+LKjKcXtjrIRvf7r57" +
1059 "R0wo//BefZnQa/Esg/DvLW0SSyEd7RcwmK1LEsmAkNHlBGsoOmRY1iaLuFGyBwMqpAzaaW" +
1060 "X8RxNz8E87dBJDkHGh4uYVigEgvlpd/Fq+o3ccwcyDc6uZdSp6zFaiSUTpx7z8Bq1t8hvQ" +
1063 "C=US, O=Equifax Secure Inc., CN=Equifax Secure Global eBusiness CA-1",
1064 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC65xeQAmWxNFU8ScJR1d+n0TeP0eeBc0" +
1065 "FSYJudoRcmeK3HsegmlDK13jONOi/b8pp6WnOYo1zp+4pzG1znw7+AbM2p9NYrwPf5mapj" +
1066 "orFHAg/U5FE6EjxsilpUhHDbwcWQz3JFy6hZwM0znT+jluuFMyEcPh4+YG52nGeFxcjDYQ" +
1069 "O=EUnet International, CN=EUnet International Root CA",
1070 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeQTvZQUmLKJxZFPdQaCh7TQhcZ/+FHg" +
1071 "umzzoyArB8fEqftokCIQxKmYvLZFF+eFq2XqlTt+/vx9+lIVmXTuIH5S18GdUqysgz05YQ" +
1072 "Lt2gAJ/9yuhhqVPKth0YPpwR4GPnKmdbyESV8BNVSLu+VbhnN83LABMN/E9pFGpRlOy8Jw" +
1075 "CN=FESTE, Public Notary Certs, EmailAddress=feste@feste.org",
1076 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhg/ObLsnn4cf0VAXNdkD+tLMTvucVXo" +
1077 "Ym6EB3GlU/0QMmjPqHX6TF+f61MonGf0GR2BVATnBS8PHa+GI1mV4clFNhzD5iwINdWNH4" +
1078 "SBFxbPewd+EYl7QHKDCRMcdPVPOEnsxZiUVtfrTJ245ClWbU3x4YTfylD9YahDnEyvK98w" +
1081 "CN=FESTE, Verified Certs",
1082 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqY58fOBqEBISzS5MZhKJ7YsOnqyzsYE" +
1083 "5VEeIEMicgNfkaeB8nZ6fggrAF6Capm4pEVr9LhFOjIqYOFlO5f68QyDMYVNnGTHzRW1ZS" +
1084 "U4amWz8T8sMB0jGhM1y8XeTcYjzKI5dPcPuBjrDZnq+T6raxJI0ELVFDPDjsJ0Nxh+g8xw" +
1087 "CN=First Data Digital Certificates Inc. Certification Authority",
1088 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDfHBQeCbm/pEByIJl5toQi9NeFksUEJO" +
1089 "gHLgLkF5UFN5V2Pfyx5Q+HDmK5LDCXJuELFWcAphXe6I3LlewCWFLAR2UzTFafCh8EwDdQ" +
1090 "gVe63/rya2fry9CAD9lXlRBlewZFWOuutF7jkxUrmby2KS/7Qp9HKy5M6zQoMpkO7/9voQ" +
1093 "C=ES, O=FNMT, OU=FNMT Clase 2 CA",
1094 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCYP60ZNpM9Pv52QhT9NW/x+q0ieljjRt" +
1095 "Bdxlr5Yi2PMV7+tDD+UHSs1p0d4GLGSd0UEn1xC6wGwT/XBofgkInW5eMDsvInsZ8zyKpr" +
1096 "NkqjxD95QZ2JRi8rPmPUOFaRqh2xDUJ1TfOHTuMPTcy0bL9iE4fq0JuOtuL/GfSUCdWWYQ" +
1099 "CN=Belgacom E-Trust Primary CA",
1100 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq2bmz1U9qTcVB0HsEYWqLcYEH2mTjWG" +
1101 "4nVcKtzhew/PqSjQjwHHL/ssMx/uBqh5dMzENXpyh5OrWDXaQdavFqxT4UIh1ZBm/wpjF3" +
1102 "3LBJOObLDA/+qnI0iNooOiFa7nQrG6TbWxMWtXNfw66M0sA+PbDL8OyLhgvCwUQYWmOo1Q" +
1105 "C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA",
1106 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2g7mmY3Oo+NPin778YuDJWvqSB" +
1107 "/xKrC5lREEvfBj0eJnZs8c3c8bSCvujYmOmq8pgGWr6cctEsurHExwB6E9CjDNFY1P+N3U" +
1108 "jFAVHO9Q7sQu9/zpUvKRfeBt1TUwjl5Dc/JB6dVq47KJOlY5OG8GPIhpWypNxadUuGyJzJ" +
1109 "v5PMrl/Yn1EjySeJbW3HRuk0Rh0Y3HRrJ1DoboGYrVbWzVeBaVounICjjr8iQTT3NUkxOF" +
1110 "Ohu8HjS1iwWMuXeLsdsfIJGrCVNukM57N3S5cEeRIlFjFnmusa5BJgjIGSvRRqpI1mQq14" +
1111 "M0/ywqwWwZQ0oHhefTfPYhaO/q8lKff5OQzwIDAQAB",
1113 "CN=GTE CyberTrust Global Root",
1114 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9p" +
1115 "TAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6" +
1116 "XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQ" +
1119 "CN=GTE CyberTrust Root",
1120 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6jr11kBL65Xl0stn3JtQOQR3pNgdWct" +
1121 "W4adpU1LHWeG2q4zs9o4Q3JcevrwTcsyKx6W2+gm3rjS+9tK5wHqLWbiAxUeZWXHNSsiNQ" +
1122 "Trz7mmdAxIYRRsdDIrrqAE9scs1hnN7L+u4w0ub6W53Fmdwg+Dm/ZIwHVju93Gxe9r/h2Q" +
1125 "C=US, O=GTE Corporation, CN=GTE CyberTrust Root",
1126 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7" +
1127 "pJjTUteueLveUFMVnGsS8KDPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3" +
1128 "FQZor734sLPwKfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44Aw" +
1131 "OU=ValiCert Class 3 Policy Validation Authority",
1132 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFl" +
1133 "LWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2" +
1134 "bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPw" +
1137 "OU=ValiCert Class 1 Policy Validation Authority",
1138 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSL" +
1139 "wxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+Fiw" +
1140 "nRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQ" +
1143 "OU=ValiCert Class 2 Policy Validation Authority",
1144 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZU" +
1145 "cOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XB" +
1146 "hVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9w" +
1149 "C=hk, O=C&W HKT SecureNet CA Class A",
1150 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtBuiCqVMc2NGUUh0Y6i0jBbb9M" +
1151 "hn3qFIAv/Lo8+n39mxMeDjLihxBKZkWsZc/tCnuOo+Ctr7EX9/JCheyIqsbniqyKIYOZ5M" +
1152 "UNHwmLXvpLIbYGu/+XO0C3X5Irvp5YGgldJ2THzTp/5dlRXtB9TH3mAwAO7yLpTxhjLlWV" +
1153 "Ho34CiKgDvPIhdEeMAX1TkDEcQbLD1+DN2HDRmW9S7NGM502aUOuzNIinz9hK71CEpN6VE" +
1154 "Td+JDAQMfUF7h/MWwUMpZLTWRWerhkxljwG36mOMTnhUREcaU4aMaxgnIQvFVmYOJfbgea" +
1155 "xoAHTpmmQ8SU6e4B3IiBtQBvddCfiNixP9XQIDAQAB",
1157 "CN=IPS SERVIDORES",
1158 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyYXZhkJAk8IbPMGb" +
1159 "WOlI6H0fg3PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1gf/+rHhwLWjhOgeYlQJU" +
1160 "3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4Nu+z4cYgjui0OLzhPvYR3oydAQ" +
1163 "CN=Microsoft Root Authority",
1164 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQK9wXDmO/JOGyifl3heMOqiqY" +
1165 "0lX/j+lUyjt/6doiA+fFGim6KPYDJr0UJkee6sdslU2vLrnIYcj5+EZrPFa3piI9YdPN4P" +
1166 "AZLolsS/LWaammgmmdA6LL8MtVgmwUbnCj44liypKDmo7EmDQuOED7uabFVhrIJ8oWAtd0" +
1167 "zpmbRkO5pQHDEIJBSfqeeRKxjmPZhjFGBYBWWfHTdSh/en75QCxhvTv1VFs4mAvzrsVJRO" +
1168 "rv2nem10Tq8YzJYJKCEAV5BgaTe7SxIHPFb/W/ukZgoIptKBVlfvtjteFoF3BNr2vq6Alf" +
1169 "6wzX/WpxpyXDzKvPAIoyIwswaFybMgdxOF3wIDAQAB",
1171 "CN=Microsoft Root Certificate Authority",
1172 "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA8136gGfUWqepDCyQINA1CDx1hM" +
1173 "23B4mcidrezsNg+pFoWp6UcSkYdnzC4MgldpQOWPoENDbm36/3gLrpWAsrk+WdBeN3IpH3" +
1174 "NGQ8IpEdXuEJkLwU/vx1WBnhebcHkqOuiFkI2J8HygNY/GgpbTLX0qjLS/zhC0gyT+bruK" +
1175 "1P5FxvE5SZ25XVdduoGreUkbR3W/VIDI9qeX0UcAR9ba+Q9dpw2Ee3v5svbOcFt+ERYKx5" +
1176 "kRR8xdam5OF+1cN+5ZLSPAC1NoLeeeFt87Vu+J8zyctSfXOYNtuLoWuilZebo97CTSb/Bp" +
1177 "ZnJQbI56zk7hIzlTGZyDUITjTKeVPVtb5jMllANsClTgRNPdtbBzPkWL/vP1Nk2EJZNVf9" +
1178 "D0V8JARNntY4dBGXIpDOaER0km/VS2+whuPHNkKg0PzBwFr5o2G5MEdxlgoWsJHAQpXvEH" +
1179 "8oauMqH7HkzQM/d3EExyD8SQ8dRYik18t+iK2OLexF28RRBMkq/OyGnpoRl1vezlOI5uK3" +
1180 "/ayVwihA2+8EkN+BMznZskWlI4cGpVWJMbsGLWAOQRh9Hy61l8sR6xXVJKWU7xUUif1Lc/" +
1181 "oyW/zRMwD5WWJwBzLqLqtALXvK3SFnGzCZjxaqI6hB0bBuEZs2xN5AdJzhWGXBYB56WzjI" +
1182 "j7sEJnzUFkDltmtsqob9AL/OwTUCAwEAAQ==",
1184 "CN=NetLock Expressz (Class C) Tanusitvanykiado",
1185 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDr7LBsYYojJa9gIOPZn/yTC9tdjbChs0" +
1186 "A6gs79deB4MgOGWoaVke1T+p1A/Obo3dlbegO9XfM7DMNReZutVaDp0AMQrwq6FELZUiYR" +
1187 "IsfSIMyCpJqp/riBdp1qt9I2dT6xhgn2bm1+Trd67K5xhPYEMwglMut0rBZExuRAkx1/rQ" +
1190 "CN=NetLock Kozjegyzoi (Class A) Tanusitvanykiado",
1191 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeL" +
1192 "Vu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX" +
1193 "9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8Wg" +
1194 "D/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7tqyF" +
1195 "/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCo" +
1196 "R64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQAB",
1198 "OU=Tanusitvanykiadok, CN=NetLock Uzleti (Class B) Tanusitvanykiado",
1199 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBN" +
1200 "wcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX" +
1201 "iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvcQ7GhaQ" +
1204 "CN=Post.Trust Root CA",
1205 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1n8T5A0k2Nj76bbDsVKjTty3O+" +
1206 "L3Dl+B5gHwpuY2cNgTc6H/UgiQ8hW88jIcqNfhBhB7QaiUxz89RBXcgFHnMP5TSPWQX21t" +
1207 "JeBgu6D71sYp+E1wUBo3oA7NeCq2aPOZ1AyOXhJi/8JfWporiEequ6HZdfAsXP5twrFbMc" +
1208 "yDhxqnvpAO6BBUU1ILnEnzgAL+byemo1cwuNu40AAEA+Tl1EMG66toTWgm0pk0ueASln9L" +
1209 "u2tuIXHmCEVKHWYNN8kD4dHK3LEvcPa3gWKWG2Sn/rvhhutBn6ic2Mqg4dYv+A/hukA492" +
1210 "3RpcpMGciW3MxJHAq206iROvna7B3Nc0okPwIDAQAB",
1212 "CN=PTT Post Root CA, 0.9.2342.19200300.100.1.3=ca@ptt-post.nl",
1213 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsH7iOgHxSK1T1HHO276A4FCtma" +
1214 "KEeto6JyQ6EYE2Eg3mo5mOpMwmtQ5hxu4oq22G3y6XYfpAacmNjMQxe/pSXlZMIJ5gGl9s" +
1215 "SnjJiTyflYasd2cOpg5C6CxiSTJLBD4yQ5AOCiLKyHQOhe+DgcVb8ttshQhvTialBqt245" +
1216 "iiTl7EgODo+8zpMGzycmGuJ35T1BWUD9KPeYLZ9o+rxhPmHJh0SwBhDnlpVPKQsqMJAWX3" +
1217 "BEdsTvopK/AOBheT3ILAEd6PsDBGWUhKZs42r8fPMdGSdBQj1aq64InbEtHs1GkjuAsWST" +
1218 "POGvninF98aB13uwGqZ+Ixxv/WOmn9DBt8IwIDAQAB",
1220 "CN=Saunalahden Serveri CA, EmailAddress=gold-certs@saunalahti.fi",
1221 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5wQp3NbgUtPWTwCvHIGIvzxUcv" +
1222 "OeeWP9y2DaDHxyL8obqeIQaWd6OZ/CoCXMg4ONgxEcuP3n26mIowySIVfBquLqM35KZgO8" +
1223 "c43SHCn9x39D7Y/rV3uhQb9NczFKNyi0GFdYPGhwUJO6EB14zZPDwoLvuN8PDFjVMFdDOh" +
1224 "QlKjhZBrREzdvJXkbyS7gcQ0GB0j5Dsq4hnhtKgHymyrP0JqkuLPi39zwYD5sybxEJc8TN" +
1225 "L+jT7Ek284GN2ML/0Bpt3dgUvzLQ6cMNPgiv7dpLnWrPE4uQgmn612cjYUtb/aWAZB1696" +
1226 "XT2ncceLtR++dGgJBxcbYW+EO0Gb0Yq952ewIDAQAB",
1228 "CN=Saunalahden Serveri CA, EmailAddress=silver-certs@saunalahti.fi",
1229 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0neMvIdsNk5TqmhgRbgjd2fj7k" +
1230 "mC5mx/XpJdtRxhUteoYEsW+ut5fp1MkulXe16GMKkoPH030SHidhoZw++q2u74AZ4aOSov" +
1231 "k3UDZj9uKU2NhGOMpx8VlLQ0SbTk00GruvvEXLWecvUoyjKCY0zHRPi0HcSKCldVkK8wiV" +
1232 "QOp2gm00AHIrPOPKP7mNckPN58gkm0NIx9JNtkbmSy6f+GyKx+q1Pk0kH0EYTuR0wIHUTm" +
1233 "Vk0AfNqJQjnveAjRhea+XJ4zuTX/HM70g7XyZMUxSKm0rMXYPIwabab/Qq3z+EvOrNrFir" +
1234 "APAyPB9fPHWX8w8d9mHVoxBaJGHTnkVbOtDwIDAQAB",
1236 "C=hk, O=C&W HKT SecureNet CA Class B",
1237 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn+AlkQ8EV8LHXLFlAmYPqP3YMQ" +
1238 "5vgmz5wx6w46C9OERSx4x2EnhMfsIrjIrk+dwK4JVF3+seftJE+AMVAOzEsTx6tk22lgp3" +
1239 "vAdg7/C3N/6J/bLYB6tS/oI/vDVnM9n7LNy1WGGiDLF9lNGohGkkPZfNmwhMUImBmh/Swi" +
1240 "BvzD8OZcThSEncO/nlKjEHbqZrR6gZWq7ToXS1vMLbOT36q7DwySIJ1DxGaGwuLh/4qIwR" +
1241 "oXY1UpLXq4gh3L3pnNn4Pt4wMUwCIi9XZrtWcjk3UJmvV9D0S9Qp7alvxtOyhpGLHRBtaB" +
1242 "Zk8Q5tv15n/bKOcGXnb3K8RHWrAXb/N2RFIQIDAQAB",
1244 "C=US, O=RSA Data Security, Inc., OU=Secure Server Certification Authority",
1245 "MIGbMA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6z" +
1246 "V4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXAT" +
1247 "cXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAA" +
1250 "C=au, O=SecureNet CA Class A",
1251 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqaN8+JCzjoRM4Aq+qxIqjQw+L7" +
1252 "XdmxCIuWq3h3Ugt0vvIiMG6/BWMvfLLXDFA2+3wdDDZhMCvVVJh4fpLZ6l5XY2q+JkJViI" +
1253 "wxsbAvBdsY+fE03CUim0EDVPNoivCy2BCCRhw2iNWm0x6FQZUxf9pxP2QJmmqCnAn0J7Jy" +
1254 "nB7tvvjQNkJYGx/pUaHtoQQWIbVn8YGEiY0k1LwRhot2lna2RMbo8CvxRpe/ZEIxDpLrxe" +
1255 "Ys1bnMyjjoxRgbSiorG8qMnoKpiqu0sVoeHpkHqef+hlBegRcXpv43XeVT/L2OrIAM0llH" +
1256 "JkHu99ED5NL5F5vQLq15DBSWhuWRQl4t3dCQIDAQAB",
1258 "C=au, O=SecureNet CA Class B",
1259 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApmPZxhVadudGZcc0kfl73Va7+J" +
1260 "Y1LinKp30KHvcxUuhayNPPOQFOW/AfsbhK0rNHQ2Y/AUBOMEnhD/3rEmN4zPYWYhj1b2n9" +
1261 "fm4zdiGjwIgP6uYl/KmXzBhyxzG2C5vNwsV4YWNFrDSmJ3hoxL1SaM6ETdIkpShsgObK5s" +
1262 "/mmp5QeM7zNtKjQ1ocBq/LIO7QLMREGJBssZFkZbm3hYNLqJGZxeCc97hQ19OwT5rtY/tN" +
1263 "9NQoJDqAW3uTjMUFhK87hv6BMce2nV8a6pB7sEZesghSAFcNVVKDeJVK/WiPntlQtktT+v" +
1264 "KFApVOOPWDp5bUMT8/p8o3U9zFL20adKbMvwIDAQAB",
1266 "C=au, O=SecureNet CA Root",
1267 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApyi02Dz1v3oGkb2lQkyzfJ6IZp" +
1268 "nF2xfURVTDe8DwJFZmmL9E4HkTdmiu3Zp0z6Lpl+bBwKnD9yzVNjtzna+C2twOX1Ov625Q" +
1269 "16jwqo6rY9Kbdf5VCnzRs8BZk1Eqh2mKGe3k19eOFKu1GVizzmzgTYLTA4TBqwAYekmoFX" +
1270 "0IyQFgJ5To+wlgntE/Ts0To3j9ZfcRX/abADCMIu0oiWUb0x9he8Mjo+PGgPmD8/e63oZ4" +
1271 "X/aVw4xqSCJlhdMiefb9RBboD2EENip1xtviZRQnYtyCXJYSMw5MGNX2PJ2xzWEcsYX5A9" +
1272 "G69kzW7p990ZIh8PYKFqQ0h/dWj5O+l69SpwIDAQAB",
1274 "C=au, O=SecureNet CA SGC Root",
1275 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp1uxDYpTIbpSiDiQQmVE/Vbrc8" +
1276 "WF8wYx5Qj8jLHVescLIwq8WgkiAfinwN5XdDGLrTbMXnP39kTwMcr1LKIF8wocMHqGM+JG" +
1277 "U/Zk1kersVOUY3fEYtMvC+pfsHUCXvgrzybz3tKt62V/vC5BhPyZmumBG6ecZsf49bKEGy" +
1278 "B1ciHHhP8CRswPpmmFfVkh1Q6nXVYVT8wfQSx/Zhuv691Bo+yp5lZK/h6nxFwiny/gC3QB" +
1279 "cMhzgwoHpGie5FEOjXQxL6LG2ggQK+8lPmyGtUbnl4PAq96wrgYa58j7736tjrCaRfGb9b" +
1280 "HoMbtkAL9/kWbNqK+V6hM6Akxb68CT5EH8rQIDAQAB",
1282 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA1",
1283 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlJAMS3EpHNr2aHl6pLrn0syNr+" +
1284 "hHkJkfxirql2PoH84XV8Yas6jHfIftNTWAurpubb4X/swtG2zvigBJFuHuBl5KB12rPdFQ" +
1285 "uJFG1NTaFdiUXA7K19q/oPdJPMi7zuomgQoULZwNN0VrQcpXizjwJh8x/M80jo93wT/jq1" +
1286 "Q8J7TOMkxVE2L8/joWJc8ba6Ijt+DqAmm79yJxbXwLGZOhl5zjkWkfaOQvfRBtj2euwRCi" +
1287 "sF5jSpf35niprSa7VMnftO7FntMl3RNoU/mP6Ozl3oHWeD7uUEC0ATysFcGCOy5/8VIni3" +
1288 "Lg59v5iynDw0orM4mrXCoH/HwjHitPCCL+wQIDAQAB",
1290 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA1",
1291 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlJAMS3EpHNr2aHl6pLrn0syNr+" +
1292 "hHkJkfxirql2PoH84XV8Yas6jHfIftNTWAurpubb4X/swtG2zvigBJFuHuBl5KB12rPdFQ" +
1293 "uJFG1NTaFdiUXA7K19q/oPdJPMi7zuomgQoULZwNN0VrQcpXizjwJh8x/M80jo93wT/jq1" +
1294 "Q8J7TOMkxVE2L8/joWJc8ba6Ijt+DqAmm79yJxbXwLGZOhl5zjkWkfaOQvfRBtj2euwRCi" +
1295 "sF5jSpf35niprSa7VMnftO7FntMl3RNoU/mP6Ozl3oHWeD7uUEC0ATysFcGCOy5/8VIni3" +
1296 "Lg59v5iynDw0orM4mrXCoH/HwjHitPCCL+wQIDAQAB",
1298 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA2",
1299 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlnuSIz9g3wk8WIAI42MJl+jkC3" +
1300 "Vh1M0Oo/LjHkO6g/+6gVwvyN6Qi0wOLyn5B9aOs6Yor4Iqe8K0Zkxx9Ax0GrjbGuhoN6n5" +
1301 "oaJuHCjNbCY8jyoznp3LtHnE2WQ9lcYzqEf75QcJ3PZtuCVCTMP7Su1bLtQHqOWTECSTWG" +
1302 "59wdAez+kp19C8X0zwFRbD2MLO41sXW5SLKGsUZyQ79FLsDW58TrSZAtvJ8w+CqwH0jN4W" +
1303 "cMa8Fwdh/xFAhOosG3o6sANhB6qWjdDauYOO5J1RaXVxZIG0iFXcEIPOLaX1MJZhLjsK/I" +
1304 "dfnFyCdRMe05jR7cntchYcDAbcWSB+8F3v9wIDAQAB",
1306 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA2",
1307 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlnuSIz9g3wk8WIAI42MJl+jkC3" +
1308 "Vh1M0Oo/LjHkO6g/+6gVwvyN6Qi0wOLyn5B9aOs6Yor4Iqe8K0Zkxx9Ax0GrjbGuhoN6n5" +
1309 "oaJuHCjNbCY8jyoznp3LtHnE2WQ9lcYzqEf75QcJ3PZtuCVCTMP7Su1bLtQHqOWTECSTWG" +
1310 "59wdAez+kp19C8X0zwFRbD2MLO41sXW5SLKGsUZyQ79FLsDW58TrSZAtvJ8w+CqwH0jN4W" +
1311 "cMa8Fwdh/xFAhOosG3o6sANhB6qWjdDauYOO5J1RaXVxZIG0iFXcEIPOLaX1MJZhLjsK/I" +
1312 "dfnFyCdRMe05jR7cntchYcDAbcWSB+8F3v9wIDAQAB",
1314 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA3",
1315 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmV4egJZmI2TOnIwAPgqvCOm4BO" +
1316 "CEuG1TdU02qLXg14xOYFW2A5ebWhqn87o92ZqUMXZ0I8n37BJd2CDUHekbojd2BA8+rBZp" +
1317 "O+H/EC9WJeQzUBMJzE4Oq/Dkddtx1fxKze3bDzUFFdWwZntCeyblWeK1x8Cyx6FD/Q8vC4" +
1318 "MlJVeBu7vRNTB0kZCyj59o1dJDt7JFqSPAVtiHEtNz/stZ6q/85x9eVEUcqm2Vk2JHQkFe" +
1319 "T+s2Bw4oeFQKfMDDJBOGAwK5rHaSSlrdxdzs+LPbK7UbNud4gkyVfiBWsnUcfZfvf5Q4Ka" +
1320 "IA4tHqseM0NjFAWLiqt86BGgwXgQ3967jTvQIDAQAB",
1322 "C=hk, O=C&W HKT SecureNet CA Root",
1323 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtBiikFaM1l2/RliRJ+qddeCk66" +
1324 "JQcIdFSUmSa7c5AEt7qNpA4eYNouA3AUhNznLhXJPTw/mSDSTvSM5HKsutkjqq1pWy8hme" +
1325 "PpV8j2ACdJMWKGn+O+5deJMcejwj6WE5bMUwLR+EkgVx53TBQkfpMLGjFww2Y89Q0DKoh6" +
1326 "VAYhQROPvOL40zsIvpjnD7sJ7HXQPu9uWNcjzIvFSSz8qQ38jbrwXx61DK0QWsBbQBFZb1" +
1327 "6zihafeDQ+g8pl2lLLokFi/7DjJwphLWmTb3axuj5/zHG8jYL3XRNbPpwtaPBB3BtX4EOz" +
1328 "iJ5KMj8P3KvczrnRcGFXLt0Ob71m+z8Z0+uwIDAQAB",
1330 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA3",
1331 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmV4egJZmI2TOnIwAPgqvCOm4BO" +
1332 "CEuG1TdU02qLXg14xOYFW2A5ebWhqn87o92ZqUMXZ0I8n37BJd2CDUHekbojd2BA8+rBZp" +
1333 "O+H/EC9WJeQzUBMJzE4Oq/Dkddtx1fxKze3bDzUFFdWwZntCeyblWeK1x8Cyx6FD/Q8vC4" +
1334 "MlJVeBu7vRNTB0kZCyj59o1dJDt7JFqSPAVtiHEtNz/stZ6q/85x9eVEUcqm2Vk2JHQkFe" +
1335 "T+s2Bw4oeFQKfMDDJBOGAwK5rHaSSlrdxdzs+LPbK7UbNud4gkyVfiBWsnUcfZfvf5Q4Ka" +
1336 "IA4tHqseM0NjFAWLiqt86BGgwXgQ3967jTvQIDAQAB",
1338 "CN=SERVICIOS DE CERTIFICACION - A.N.C.",
1339 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsiov7CtZakOTiUYqiuXs+gX64s" +
1340 "jeQWuvA9sAWu9IN89XifvdyZIQ3ncDlRyQPse2ZyU7VZjv2Tz+JuSKO0SpdDeDCncndLip" +
1341 "ca3dlxPSyqIuuLqdyb5Z6Nly8oqFZhxHXrSHgtYP32cmpr02sfNdkFBRdjIsOy+qX2Fe41" +
1342 "TVEl3/DY0Rx4J6Nt/hTBbEdN0tau/QsfAzp/6/N2dDEi55SpSvhPsHEQhOMJN16QFUzsXe" +
1343 "FIbwrq6bciUPRHfi82yveZwuSceemHYyFpq8AN7gtCAFkRfdgBUU7jZBxCGP7tkAShnGcW" +
1344 "GlEV0AO+SndGw6Sm6D4HoxXCFl+AiHQodn5QIDAQAB",
1346 "CN=SIA Secure Client CA",
1347 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDS/LBAYGpmY1Jm5mkJcY2BmB4dHfPgSQ" +
1348 "3IK2/Qd1FFxZ1uo1xw3hV4Fh5f4MJi9H0yQ3cI19/S9X83glLGfpOd8U1naMIvwiWIHXHm" +
1349 "2ArQeORRQjlVBvOAYv6WpW3FRsdB5QASm2bB4o2VPtXHDFj3yGCknHhxlYzeegm/HNX8ow" +
1352 "C=IT, O=SIA S.p.A., L=Milano, CN=SIA Secure Server CA",
1353 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA28ELzCfTEiIuuWQWdKxZJ+IqkA" +
1354 "CSntWYXCtRbhsTb1RvShCihethC+ztnH7Of2WTbsxsQZzILarGs5v7THCcEXXzcom6iQCt" +
1355 "xy5J53PagLIs/vKXmfQCGzQvOaqL5u8F/Ln1ulR/ob+OHkg2Mwl0Yac9x5skx8OJzcpOKD" +
1356 "EjBhxiFY7fTxtrLUri9LDczvOQ/XmBE8E+Lma8+SJNCy9iM42oK+rpb3OnN5QEL+leTQ3p" +
1357 "7XwyP3lK5jp2KSBQ84+CRHJsMDRIWKpdGz8B6yHs6n6oK4Rd9sExlU8pe7U1t/60BlewFN" +
1358 "fyVVmMupu5MT/lqqrvJXCVkjZB8VWfwQhEnQIDAQAB",
1360 "OU=Public CA Services",
1361 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwOeC2xUTrnnCtF+SjyO8uvfG0Q" +
1362 "Cv1lRp8V2mYvhh0Zzeyjss6VwWJzTmuNHKdO8leGRt/hzoiXMxU2dnhsStamjnClZEgzpY" +
1363 "R4l3Gtpv8vkHQMk9Ae9q0dlrhJ7FaytOtyz4pGpXq2gxuhlmuuwbV/vOStZLeMPBgT1Llj" +
1364 "CZqcMt4uQSJgqkYxIc1HfIgdSnVUMt/ARWndwLrrdsCtozkIgFyX5UgujSMtDXAUkqNZB5" +
1365 "OXPWi7xhzYdtUBUFTKnoSkcxiwXM5flC1xJg+Do/o6k2GqWGNiymBIMJ9lLFsH0fiEGQmM" +
1366 "VlaJYQshPJFkm9Kr6wSKfC/S1eVtA3TVhR+wIDAQAB",
1368 "OU=TC TrustCenter Class 1 CA",
1369 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwKeu0drOu17ZbtF7nveOxnEkEV1uhq9" +
1370 "l/Exv9umGr2Odx3y0AlF1RSH0j73VihJA8Ch9ZEXQvjoCl/TACPSlSzXIaSSGcvMtSjkih" +
1371 "Y5bIEIUwaVd0RcBahsbVPeBoV30xaiSNRZc+MX5oZjJuJG3sMjbJQcrwMUTIo2HKG6A2Hw" +
1374 "OU=TC TrustCenter Class 2 CA",
1375 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaOOjtMgApcYMBDb+MAdzaxq05pKmKL9" +
1376 "WLXGhfUMZi9Wa9ypEi7KodUdc9s1Gyg05dy0mw8ExV5Wstx4ULMBySToLUygLt92++3ODj" +
1377 "FLgFU/Ka9FaLWp6Fk9G0glauTbuoS1cWvP74WJ74KY2we814yU+si2cM8Zz7/FebV1xPDQ" +
1380 "OU=TC TrustCenter Class 3 CA",
1381 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2tME1BS4NjeygQGocDiemUJJrUBsH3i" +
1382 "7ndszg2vyEqF6MY2orTdlOAnYRwQvyjXnKALbxsA7X+6QXPa+raXqWJ7+vM6GaKlmqxLU3" +
1383 "CPISpTG2Q/UylnEoKKuNKIbfu+7jDH0w1sNSq49dJ5xrwKPnBWtXSUSzbupkz9KOelB3dw" +
1386 "OU=TC TrustCenter Class 4 CA",
1387 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/L2PWNnuyDdNV9WRs5iVdxrTIFLolOI" +
1388 "PrVmKlVallo/QjmcJLudDNVGemo6CjqTMrduS9rXey7VwSdMPFtg9SmnKTQ5BiZhUPRaXd" +
1389 "4N24b0BuV8F5cqNgqrp2HRKJU1r8Ar7hCRPFSi/cPYsZrdeLJEX7TPTNXDUdKUxR8/JsVQ" +
1392 "CN=Thawte Premium Server CA",
1393 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSNjZqi9fCW57agUFijzjuSQRV1tDvHB" +
1394 "uVFkfvGEg1OlL0K2oGjzsv6lbjr4aNnhf3nrRldQJN78sJoiFR2JvQZ9C6DZIGFHPUk8uX" +
1395 "KgCcXE4MvPoVUvzyRG7aEUpuCJ8vLeP5qjqGc7ZGU1jIiQW9gxG4cz+qB430Qk3nQJ0cNw" +
1398 "C=hk, O=C&W HKT SecureNet CA SGC Root",
1399 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqFNPj0Pdr+zBtA0bX7cIoprIQu" +
1400 "Nt1yUa3+DKvC8iJPlpIr0arVHncfe1dtTzPsg+EdBNe5keGLeezT5hG0URS1sm3Ck8AE0R" +
1401 "2h2Pnh903hVAvDDJD9/4LXzYjZ2g4J+wzydgzzgRCO82L3xONh0mAqf01FBDgUnr3beWFD" +
1402 "BjMtEDzSG8N5EePmWuFoL2FWBLUTuW5RnowvemBYE6qH8YWD53w1kAg/T1eUlgpy4DPgH9" +
1403 "heLfoZqJ2fhkCiuEzUPNJTUAXjBmdKHHCHWsSSeC17CVNW4dmYDrkqAtWtY4u7VHJ6sazL" +
1404 "9TU8FGsm/o101XEd2wNUgfqybqVg24CjC22wIDAQAB",
1406 "CN=Thawte Server CA",
1407 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTpFBuyP9Wa+bPXbbqDGh1R6KqwtqEJf" +
1408 "yo9EdR2oW1IHSUhh4PdcnpCGH1Bm0wbhUZAulSwGLbTZme4moMRDjN/r7jZAlwxf6xaym2" +
1409 "L0nIO9QnBCUQly/nkG3AKEKZ10xD3sP1IW1Un13DWOHA5NlbsLjctHvfNjrCtWYiEtaHDQ" +
1412 "CN=UTN - DATACorp SGC",
1413 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLi" +
1414 "t6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZD0/W" +
1415 "w5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK4ESGoE1O1k" +
1416 "duSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykqlXvY8qdOD1R8oQ2A" +
1417 "swkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv33i+Ybqypa4ETLyorG" +
1418 "kVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB",
1420 "CN=UTN-USERFirst-Hardware",
1421 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsffDOD+0qH/POYJRZ9Btn9L/WP" +
1422 "PnnyvsDYlUmbk4mRb34CF5SMK7YXQSlh08anLVPBBnOjntKxPNZuuVCTOkbJex6MbswXV5" +
1423 "nEZejavQav25KlUXEFSzGfCa9vGxXbanbfvgcRdrooj7AN/+GjF3DJoBerEy4ysBBzhuw6" +
1424 "VeI7xFm3tQwckwj9vlK3rTW/szQB6g1ZgXvIuHw4nTXaCOsqqq9o5piAbF+okh8widaS4J" +
1425 "M5spDUYPjMxJNLBpUb35Bs1orWZMvD6sYb0KiA7I3z3ufARMnQpea5HW7sftKI2rTYeJc9" +
1426 "BupNAeFosU4XZEA39jrOTNSZzFkvSrMqFIWwIDAQAB",
1428 "CN=UTN-USERFirst-Network Applications",
1429 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/uRoeQ2VYWsBjRboJpYsvi1Dw" +
1430 "V3g64ysXaSaOwjSsl2P+Octjd5A7mraY0HJbYZZ+SwGxhzYUrofs3TL2TjpnwM+heAow1H" +
1431 "iU9RcS/u/D/5uBaAh4mTJSCaQ4JpJHYoWTWhHcB/gwZkFiAs00mkhbTAYX9RCPhoFZGAy6" +
1432 "XV7js69IQEXmBZp4w0cu64eMXROxJKb35lJ7mkVcW5b0OkxR0smcBSpHhMFbNAmAhrQ8YB" +
1433 "sHp79WscIj/L7/+o0DpLdhWe0tHGLuPbVxsyorhv6IamP3Cr5XCSq0QeQFD7nKNi5GxuoM" +
1434 "je4oBC+ukv6M4yBI98jbccozU8Fd2ew66XpQIDAQAB",
1436 "CN=VeriSign Class 3 Public Primary Certification Authority - G3",
1437 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy7qcUvx4Hxoebxs3c734yWuUEj" +
1438 "BP8DZH9dCRCvUXyKVhwRZATfuKYZDldiDBEQZ9qyxupvURQY76La0qYVmkZyZM0Oi8Ultw" +
1439 "IARY0XrJpGm8gxdkrQWLvNBYzo2M9evwQkkLnZcnZzJu4a6TFRxwvCBNLxjekojobIVXER" +
1440 "rpfuMmEVSiRZZVg8owiejc2KPtKoA/f3llVz4VIGYIL5WTv6pHL6hGl/AS4v7CCitR5nbm" +
1441 "t0a34g2mzKjDTFlVieboU1wc6p3wYhYLp8lfDPDewnbOr/dq8vpBpqIzFMnlemPTnmI31Y" +
1442 "Vlng7mUyR0G14dElNbxyzng0k7Fa6KaLlXlwIDAQAB",
1444 "CN=VeriSign Class 4 Public Primary Certification Authority - G3",
1445 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArculEWnGWavxj7UZD1bOzLUfIO" +
1446 "SeJiVL4HNliVne0IPk9Q+1u63xfOgh/OToDO58RSIZdpK0E7cgWwn6Ya6o8qWNhcIq1t5m" +
1447 "NtKbAvSokmB8nGm0jyQe0IZS9jKcQVgeIr3NRWKVCG7QZt1ToszwENxUc4sEoUYzM1wXQL" +
1448 "meTdPzvlWD6LGJjlp8mpYikDuIJfLSU4gCDAt48uY3F0swRgfkgG2m2JYu6Cz4EbM4DWam" +
1449 "m+rJI1vbjuLzE44aWS2qAvDspIdm3ME/9di59OyCxtI9lR3lwE+EydmjRCgGatdFrPBrau" +
1450 "9OX/gRgh44YzRmUNQ+k3P6MMNmrf+TLZfvAwIDAQAB",
1452 "OU=VeriSign Trust Network",
1453 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRN" +
1454 "zjMHPVKmIquNDMHO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDH" +
1455 "qGKB3FtKqsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHw" +
1458 "OU=VeriSign Trust Network",
1459 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRN" +
1460 "zjMHPVKmIquNDMHO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDH" +
1461 "qGKB3FtKqsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHw" +
1464 "OU=VeriSign Trust Network",
1465 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm" +
1466 "1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71" +
1467 "lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZw" +
1470 "OU=VeriSign Trust Network",
1471 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm" +
1472 "1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71" +
1473 "lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZw" +
1478 static class entropySpinner extends Thread {
1479 volatile boolean stop = false;
1481 entropySpinner() { start(); }
1482 public void run() { while (!stop) counter++; }
1487 entropySpinner[] spinners = new entropySpinner[10];
1488 for(int i=0; i<spinners.length; i++) spinners[i] = new entropySpinner();
1490 for(int i=0; i<pad1.length; i++) pad1[i] = (byte)0x36;
1491 for(int i=0; i<pad2.length; i++) pad2[i] = (byte)0x5C;
1492 for(int i=0; i<pad1_sha.length; i++) pad1_sha[i] = (byte)0x36;
1493 for(int i=0; i<pad2_sha.length; i++) pad2_sha[i] = (byte)0x5C;
1496 if (Log.on) Log.log(TinySSL.class, "reading in trusted root public keys...");
1497 trusted_CA_public_keys = new SubjectPublicKeyInfo[base64_encoded_trusted_CA_public_keys.length / 2];
1498 trusted_CA_public_key_identifiers = new String[base64_encoded_trusted_CA_public_keys.length / 2];
1499 for(int i=0; i<base64_encoded_trusted_CA_public_keys.length; i+=2) {
1500 trusted_CA_public_key_identifiers[i/2] = base64_encoded_trusted_CA_public_keys[i];
1501 byte[] b = Base64.decode(base64_encoded_trusted_CA_public_keys[i+1]);
1502 DERInputStream dIn = new DERInputStream(new ByteArrayInputStream(b));
1503 trusted_CA_public_keys[i/2] = new SubjectPublicKeyInfo((DERConstructedSequence)dIn.readObject());
1506 } catch (Exception e) {
1507 if (Log.on) Log.log(TinySSL.class, e);
1510 randpool = new byte[10];
1511 try { Thread.sleep(100); } catch (Exception e) { }
1512 for(int i=0; i<spinners.length; i++) {
1513 spinners[i].stop = true;
1514 randpool[i] = spinners[i].counter;
1517 MD5Digest md5 = new MD5Digest();
1518 md5.update(randpool, 0, randpool.length);
1519 intToBytes(System.currentTimeMillis(), randpool, 0, 4); md5.update(randpool, 0, 4);
1520 intToBytes(Runtime.getRuntime().freeMemory(), randpool, 0, 4); md5.update(randpool, 0, 4);
1521 intToBytes(Runtime.getRuntime().totalMemory(), randpool, 0, 4); md5.update(randpool, 0, 4);
1522 intToBytes(System.identityHashCode(TinySSL.class), randpool, 0, 4); md5.update(randpool, 0, 4);
1523 Properties p = System.getProperties();
1524 for(Enumeration e = p.propertyNames(); e.hasMoreElements();) {
1525 String s = (String)e.nextElement();
1526 byte[] b = s.getBytes();
1527 md5.update(b, 0, b.length);
1528 b = p.getProperty(s).getBytes();
1529 md5.update(b, 0, b.length);
1531 randpool = new byte[md5.getDigestSize()];
1532 md5.doFinal(randpool, 0);
1538 * A PKCS1 encoder which uses TinySSL's built-in PRNG instead of java.security.SecureRandom.
1539 * This code was derived from BouncyCastle's org.bouncycastle.crypto.encoding.PKCS1Encoding.
1541 private static class PKCS1 implements AsymmetricBlockCipher {
1542 private static int HEADER_LENGTH = 10;
1543 private AsymmetricBlockCipher engine;
1544 private boolean forEncryption;
1545 private boolean forPrivateKey;
1547 public PKCS1(AsymmetricBlockCipher cipher) { this.engine = cipher; }
1548 public AsymmetricBlockCipher getUnderlyingCipher() { return engine; }
1550 public void init(boolean forEncryption, CipherParameters param) {
1551 engine.init(forEncryption, (AsymmetricKeyParameter)param);
1552 this.forPrivateKey = ((AsymmetricKeyParameter)param).isPrivate();
1553 this.forEncryption = forEncryption;
1556 public int getInputBlockSize() { return engine.getInputBlockSize() - (forEncryption ? HEADER_LENGTH : 0); }
1557 public int getOutputBlockSize() { return engine.getOutputBlockSize() - (forEncryption ? 0 : HEADER_LENGTH); }
1559 public byte[] processBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1560 return forEncryption ? encodeBlock(in, inOff, inLen) : decodeBlock(in, inOff, inLen);
1563 private byte[] encodeBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1564 byte[] block = new byte[engine.getInputBlockSize()];
1565 if (forPrivateKey) {
1566 block[0] = 0x01; // type code 1
1567 for (int i = 1; i != block.length - inLen - 1; i++)
1568 block[i] = (byte)0xFF;
1570 getRandomBytes(block, 0, block.length);
1571 block[0] = 0x02; // type code 2
1573 // a zero byte marks the end of the padding, so all
1574 // the pad bytes must be non-zero.
1575 for (int i = 1; i != block.length - inLen - 1; i++)
1576 while (block[i] == 0)
1577 getRandomBytes(block, i, 1);
1580 block[block.length - inLen - 1] = 0x00; // mark the end of the padding
1581 System.arraycopy(in, inOff, block, block.length - inLen, inLen);
1582 return engine.processBlock(block, 0, block.length);
1585 private byte[] decodeBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1586 byte[] block = engine.processBlock(in, inOff, inLen);
1587 if (block.length < getOutputBlockSize())
1588 throw new InvalidCipherTextException("block truncated");
1589 if (block[0] != 1 && block[0] != 2)
1590 throw new InvalidCipherTextException("unknown block type");
1592 // find and extract the message block.
1594 for (start = 1; start != block.length; start++)
1595 if (block[start] == 0)
1597 start++; // data should start at the next byte
1599 if (start >= block.length || start < HEADER_LENGTH)
1600 throw new InvalidCipherTextException("no data in block");
1602 byte[] result = new byte[block.length - start];
1603 System.arraycopy(block, start, result, 0, result.length);