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(); }
1484 // without this synchronization, GCJ will over-optimize this loop into an infinite loop. Argh.
1485 synchronized(this) {
1495 entropySpinner[] spinners = new entropySpinner[10];
1496 for(int i=0; i<spinners.length; i++) spinners[i] = new entropySpinner();
1498 for(int i=0; i<pad1.length; i++) pad1[i] = (byte)0x36;
1499 for(int i=0; i<pad2.length; i++) pad2[i] = (byte)0x5C;
1500 for(int i=0; i<pad1_sha.length; i++) pad1_sha[i] = (byte)0x36;
1501 for(int i=0; i<pad2_sha.length; i++) pad2_sha[i] = (byte)0x5C;
1504 if (Log.on) Log.log(TinySSL.class, "reading in trusted root public keys...");
1505 trusted_CA_public_keys = new SubjectPublicKeyInfo[base64_encoded_trusted_CA_public_keys.length / 2];
1506 trusted_CA_public_key_identifiers = new String[base64_encoded_trusted_CA_public_keys.length / 2];
1507 for(int i=0; i<base64_encoded_trusted_CA_public_keys.length; i+=2) {
1508 trusted_CA_public_key_identifiers[i/2] = base64_encoded_trusted_CA_public_keys[i];
1509 byte[] b = Base64.decode(base64_encoded_trusted_CA_public_keys[i+1]);
1510 DERInputStream dIn = new DERInputStream(new ByteArrayInputStream(b));
1511 trusted_CA_public_keys[i/2] = new SubjectPublicKeyInfo((DERConstructedSequence)dIn.readObject());
1514 } catch (Exception e) {
1515 if (Log.on) Log.log(TinySSL.class, e);
1518 randpool = new byte[10];
1519 try { Thread.sleep(100); } catch (Exception e) { }
1520 for(int i=0; i<spinners.length; i++) {
1521 spinners[i].stop = true;
1522 randpool[i] = spinners[i].counter;
1525 MD5Digest md5 = new MD5Digest();
1526 md5.update(randpool, 0, randpool.length);
1527 intToBytes(System.currentTimeMillis(), randpool, 0, 4); md5.update(randpool, 0, 4);
1528 intToBytes(Runtime.getRuntime().freeMemory(), randpool, 0, 4); md5.update(randpool, 0, 4);
1529 intToBytes(Runtime.getRuntime().totalMemory(), randpool, 0, 4); md5.update(randpool, 0, 4);
1530 intToBytes(System.identityHashCode(TinySSL.class), randpool, 0, 4); md5.update(randpool, 0, 4);
1531 Properties p = System.getProperties();
1532 for(Enumeration e = p.propertyNames(); e.hasMoreElements();) {
1533 String s = (String)e.nextElement();
1534 byte[] b = s.getBytes();
1535 md5.update(b, 0, b.length);
1536 b = p.getProperty(s).getBytes();
1537 md5.update(b, 0, b.length);
1539 randpool = new byte[md5.getDigestSize()];
1540 md5.doFinal(randpool, 0);
1546 * A PKCS1 encoder which uses TinySSL's built-in PRNG instead of java.security.SecureRandom.
1547 * This code was derived from BouncyCastle's org.bouncycastle.crypto.encoding.PKCS1Encoding.
1549 private static class PKCS1 implements AsymmetricBlockCipher {
1550 private static int HEADER_LENGTH = 10;
1551 private AsymmetricBlockCipher engine;
1552 private boolean forEncryption;
1553 private boolean forPrivateKey;
1555 public PKCS1(AsymmetricBlockCipher cipher) { this.engine = cipher; }
1556 public AsymmetricBlockCipher getUnderlyingCipher() { return engine; }
1558 public void init(boolean forEncryption, CipherParameters param) {
1559 engine.init(forEncryption, (AsymmetricKeyParameter)param);
1560 this.forPrivateKey = ((AsymmetricKeyParameter)param).isPrivate();
1561 this.forEncryption = forEncryption;
1564 public int getInputBlockSize() { return engine.getInputBlockSize() - (forEncryption ? HEADER_LENGTH : 0); }
1565 public int getOutputBlockSize() { return engine.getOutputBlockSize() - (forEncryption ? 0 : HEADER_LENGTH); }
1567 public byte[] processBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1568 return forEncryption ? encodeBlock(in, inOff, inLen) : decodeBlock(in, inOff, inLen);
1571 private byte[] encodeBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1572 byte[] block = new byte[engine.getInputBlockSize()];
1573 if (forPrivateKey) {
1574 block[0] = 0x01; // type code 1
1575 for (int i = 1; i != block.length - inLen - 1; i++)
1576 block[i] = (byte)0xFF;
1578 getRandomBytes(block, 0, block.length);
1579 block[0] = 0x02; // type code 2
1581 // a zero byte marks the end of the padding, so all
1582 // the pad bytes must be non-zero.
1583 for (int i = 1; i != block.length - inLen - 1; i++)
1584 while (block[i] == 0)
1585 getRandomBytes(block, i, 1);
1588 block[block.length - inLen - 1] = 0x00; // mark the end of the padding
1589 System.arraycopy(in, inOff, block, block.length - inLen, inLen);
1590 return engine.processBlock(block, 0, block.length);
1593 private byte[] decodeBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1594 byte[] block = engine.processBlock(in, inOff, inLen);
1595 if (block.length < getOutputBlockSize())
1596 throw new InvalidCipherTextException("block truncated");
1597 if (block[0] != 1 && block[0] != 2)
1598 throw new InvalidCipherTextException("unknown block type");
1600 // find and extract the message block.
1602 for (start = 1; start != block.length; start++)
1603 if (block[start] == 0)
1605 start++; // data should start at the next byte
1607 if (start >= block.length || start < HEADER_LENGTH)
1608 throw new InvalidCipherTextException("no data in block");
1610 byte[] result = new byte[block.length - start];
1611 System.arraycopy(block, start, result, 0, result.length);