1 // Copyright (C) 2003 Adam Megacz <adam@ibex.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
8 // FIXME!!! PKCS1 disabled because jc1 chokes on it after NanoGoatification
10 package org.ibex.util;
12 import org.bouncycastle.crypto.AsymmetricBlockCipher;
13 import org.bouncycastle.crypto.Digest;
14 import org.bouncycastle.crypto.CipherParameters;
15 import org.bouncycastle.crypto.InvalidCipherTextException;
16 import org.bouncycastle.crypto.params.RSAKeyParameters;
17 import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
18 import org.bouncycastle.crypto.params.KeyParameter;
19 import org.bouncycastle.crypto.digests.SHA1Digest;
20 import org.bouncycastle.crypto.digests.MD5Digest;
21 import org.bouncycastle.crypto.digests.MD2Digest;
22 import org.bouncycastle.crypto.engines.RSAEngine;
23 import org.bouncycastle.crypto.engines.RC4Engine;
24 import org.bouncycastle.util.encoders.Base64;
25 import org.bouncycastle.asn1.DERInputStream;
26 import org.bouncycastle.asn1.DEROutputStream;
27 import org.bouncycastle.asn1.DERSequence;
28 import org.bouncycastle.asn1.DERObject;
29 import org.bouncycastle.asn1.DEROctetString;
30 import org.bouncycastle.asn1.BERInputStream;
31 import org.bouncycastle.asn1.x509.X509CertificateStructure;
32 import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
33 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
34 import org.bouncycastle.asn1.x509.TBSCertificateStructure;
35 import org.bouncycastle.asn1.x509.X509Name;
36 import org.bouncycastle.asn1.x509.X509Extensions;
37 import org.bouncycastle.asn1.x509.X509Extension;
38 import org.bouncycastle.asn1.x509.BasicConstraints;
39 import org.ibex.util.Log;
48 TinySSL: a tiny SSL implementation in Java, built on the
49 bouncycastle.org lightweight crypto library.
51 This class implements an SSLv3 client-side socket, with the
52 SSL_RSA_EXPORT_WITH_RC4_40_MD5 and SSL_RSA_WITH_RC4_128_MD5 cipher
53 suites, as well as certificate chain verification against a
54 collection of 93 built-in Trusted Root CA public keys (the same 93
55 included with Microsoft Internet Explorer 5.5 SP2).
57 As of 07-Dec-01, the zipped bytecode for this class is 43k, and the
58 subset of bouncycastle it requires is 82k.
60 This class should work correctly on any Java 1.1 compliant
61 platform. The java.security.* classes are not used.
63 The main design goal for this class was the smallest possible body
64 of code capable of connecting to 99% of all active HTTPS
65 servers. Although this class is useful in many other situations
66 (IMAPS, Secure SMTP, etc), the author will refuse all feature
67 requests and submitted patches which go beyond this scope.
69 Because of the limited goals of this class, certain abstractions
70 have been avoided, and certain parameters have been
71 hard-coded. "Magic numbers" are often used instead of "static final
72 int"'s, although they are usually accompanied by a descriptive
73 comment. Numeric offsets into byte arrays are also favored over
74 DataInputStream(ByteArrayInputStream(foo))'s.
76 Much thanks and credit go to the BouncyCastle team for producing
77 such a first-class library, and for helping me out on the
78 dev-crypto mailing list while I was writing this.
82 1.0 07-Dec-01 Initial Release
84 1.01 15-Mar-02 Added PKCS1 class to avoid dependancy on java.security.SecureRandom
86 1.02 27-Mar-02 Fixed a bug which would hang the connection when more than one
87 Handshake message appeared in the same TLS Record
89 1.03 10-Aug-02 Fixed a vulnerability outlined at
90 http://online.securityfocus.com/archive/1/286290
92 1.04 12-Dec-03 Renamed to org.ibex.SSL, fixed race condition
96 public class SSL extends Socket {
98 // Simple Test //////////////////////////////////////////////
100 public static void main(String[] args) {
103 Socket s = new SSL("www.paypal.com", 443);
104 PrintWriter pw = new PrintWriter(s.getOutputStream());
105 BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
106 pw.println("GET / HTTP/1.0");
111 String s2 = br.readLine();
112 if (s2 == null) return;
113 Log.info(SSL.class, s2);
116 } catch (Exception e) {
121 // Static Data //////////////////////////////////////////////
123 public static class SSLException extends IOException { public SSLException(String s) { super(s); } }
124 static SubjectPublicKeyInfo[] trusted_CA_public_keys;
125 static String[] trusted_CA_public_key_identifiers;
126 public static byte[] pad1 = new byte[48];
127 public static byte[] pad2 = new byte[48];
128 public static byte[] pad1_sha = new byte[40];
129 public static byte[] pad2_sha = new byte[40];
130 static byte[] randpool;
131 static long randcnt = 0;
133 // Cipher State //////////////////////////////////////////////
135 public byte[] server_random = new byte[32];
136 public byte[] client_random = new byte[32];
137 public byte[] client_write_MAC_secret = new byte[16];
138 public byte[] server_write_MAC_secret = new byte[16];
139 public byte[] client_write_key = null;
140 public byte[] server_write_key = null;
141 public byte[] master_secret = null;
143 /** the bytes of the ServerKeyExchangeMessage, null if none recieved */
144 public byte[] serverKeyExchange = null;
146 /** true iff the server asked for a certificate */
147 public boolean cert_requested = false;
149 public X509CertificateStructure server_cert = null;
151 public SSLOutputStream os = null;
152 public SSLInputStream is = null;
156 /** if true, we don't mind if the server's cert isn't signed by a CA. USE WITH CAUTION! */
157 boolean ignoreUntrustedCert = false;
159 /** the concatenation of all the bytes of all handshake messages sent or recieved */
160 public byte[] handshakes = new byte[] { };
162 /** true iff we're using SSL_RSA_EXPORT_WITH_RC4_40_MD5 */
163 boolean export = false;
165 public InputStream getInputStream() throws IOException { return is != null ? is : super.getInputStream(); }
166 public OutputStream getOutputStream() throws IOException { return os != null ? os : super.getOutputStream(); }
168 public SSL(String host, int port) throws IOException { this(host, port, true, false); }
169 public SSL(String host, int port, boolean negotiateImmediately) throws IOException { this(host, port, negotiateImmediately, false); }
170 public SSL(String host, int port, boolean negotiateImmediately, boolean ignoreUntrustedCert) throws IOException {
172 if (!initializationFinished) {
173 synchronized(SSL.class) {
174 while (!initializationFinished)
175 try { SSL.class.wait(); } catch (Exception e) { }
179 this.ignoreUntrustedCert = ignoreUntrustedCert;
180 if (negotiateImmediately) negotiate();
183 /** negotiates the SSL connection */
184 public void negotiate() throws IOException {
185 os = new SSLOutputStream(super.getOutputStream());
186 is = new SSLInputStream(super.getInputStream());
187 os.writeClientHello();
188 is.readServerHandshakes();
189 os.sendClientHandshakes();
190 is.readServerFinished();
193 class SSLInputStream extends InputStream {
195 /** the underlying inputstream */
198 /** the server's sequence number */
199 public int seq_num = 0;
201 /** the decryption engine */
202 public RC4Engine rc4 = null;
204 /** pending bytes -- decrypted, but not yet fed to consumer */
209 public void mark() { }
210 public void reset() { }
211 public boolean markSupported() { return false; }
212 public long skip(long l) throws IOException { for(long i=0; i<l; i++) read(); return l; }
213 public SSLInputStream(InputStream raw) { this.raw = new DataInputStream(raw); }
214 public int available() throws IOException { return pendlen; }
216 public int read() throws IOException {
217 byte[] singlebyte = new byte[1];
218 int numread = read(singlebyte);
219 if (numread != 1) return -1;
220 return (int)singlebyte[0];
223 public int read(byte[] b, int off, int len) throws IOException {
226 if (pend == null) return -1;
228 pendlen = pend.length;
230 int ret = Math.min(len, pendlen);
231 System.arraycopy(pend, pendstart, b, off, ret);
237 /** reads and decrypts exactly one record; blocks if unavailable */
238 public byte[] readRecord() throws IOException {
240 // we only catch EOFException here, because anywhere else
241 // would be "unusual", and we *want* and EOFException in
244 try { type = raw.readByte();
245 } catch (EOFException e) {
246 if (Log.on) Log.info(this, "got EOFException reading packet type");
250 byte ver_major = raw.readByte();
251 byte ver_minor = raw.readByte();
252 short len = raw.readShort();
253 if (Log.on) Log.info(this, "got record of type " + type + ", SSLv" + ver_major + "." + ver_minor + ", length=" + len);
255 byte[] ret = new byte[len];
258 // simply ignore ChangeCipherSpec messages -- we change as soon as we send ours
260 if (Log.on) Log.info(this, "got ChangeCipherSpec; ignoring");
265 byte[] decrypted_payload;
267 // if crypto hasn't been enabled yet; skip crypt and hash
268 if (rc4 == null) decrypted_payload = ret;
270 // decrypt the payload
271 decrypted_payload = new byte[len - 16];
272 rc4.processBytes(ret, 0, len - 16, decrypted_payload, 0);
275 byte[] MAC = new byte[16];
276 rc4.processBytes(ret, len - 16, 16, MAC, 0);
277 byte[] ourMAC = computeMAC(type, decrypted_payload, 0, decrypted_payload.length, server_write_MAC_secret, seq_num++);
278 for(int i=0; i<MAC.length; i++)
279 if (MAC[i] != ourMAC[i])
280 throw new SSLException("MAC mismatch on byte " + i + ": got " + MAC[i] + ", expecting " + ourMAC[i]);
284 if (decrypted_payload[1] > 1) {
285 throw new SSLException("got SSL ALERT message, level=" + decrypted_payload[0] + " code=" + decrypted_payload[1]);
286 } else if (decrypted_payload[1] == 0) {
287 if (Log.on) Log.info(this, "server requested connection closure; returning null");
290 if (Log.on) Log.info(this, "got SSL ALERT message, level=" + decrypted_payload[0] + " code=" + decrypted_payload[1]);
294 } else if (type == 22) {
295 if (Log.on) Log.info(this, "read a handshake");
297 } else if (type != 23) {
298 if (Log.on) Log.info(this, "unexpected record type: " + type + "; skipping");
303 if (Log.on) Log.info(this, " returning " + decrypted_payload.length + " byte record payload");
304 return decrypted_payload;
307 private byte[] readHandshake() throws IOException {
308 // acquire a handshake message
309 byte type = (byte)read();
310 int len = ((read() & 0xff) << 16) | ((read() & 0xff) << 8) | (read() & 0xff);
311 byte[] rec = new byte[len + 4];
313 rec[1] = (byte)(((len & 0x00ff0000) >> 16) & 0xff);
314 rec[2] = (byte)(((len & 0x0000ff00) >> 8) & 0xff);
315 rec[3] = (byte)((len & 0x000000ff) & 0xff);
316 if (len > 0) read(rec, 4, len);
320 /** This reads the ServerHello, Certificate, and ServerHelloDone handshake messages */
321 public void readServerHandshakes() throws IOException {
324 byte[] rec = readHandshake();
325 handshakes = concat(new byte[][] { handshakes, rec });
328 case 2: // ServerHello
329 if (Log.on) Log.info(this, "got ServerHello");
330 byte ver_major = rec[4];
331 byte ver_minor = rec[5];
332 System.arraycopy(rec, 6, server_random, 0, server_random.length);
333 short cipher_high = rec[6 + server_random.length + rec[6 + server_random.length] + 1];
334 short cipher_low = rec[6 + server_random.length + rec[6 + server_random.length] + 2];
336 if (cipher_low == 0x04 || cipher_high != 0x00) {
338 if (Log.on) Log.info(this, "using SSL_RSA_WITH_RC4_128_MD5");
340 } else if (cipher_low == 0x03 || cipher_high != 0x00) {
342 if (Log.on) Log.info(this, "using SSL_RSA_EXPORT_WITH_RC4_40_MD5");
344 } else throw new SSLException("server asked for cipher " + ((cipher_high << 8) | cipher_low) +
345 " but we only do SSL_RSA_WITH_RC4_128_MD5 (0x0004) and " +
346 "SSL_RSA_EXPORT_WITH_RC4_40_MD5 (0x0003)");
348 byte compressionMethod = rec[6 + server_random.length + rec[6 + server_random.length] + 3];
349 if (compressionMethod != 0x0) throw new SSLException("server asked for compression method " + compressionMethod +
350 " but we don't support compression");
353 case 11: // Server's certificate(s)
354 if (Log.on) Log.info(this, "got Server Certificate(s)");
355 int numcertbytes = ((rec[4] & 0xff) << 16) | ((rec[5] & 0xff) << 8) | (rec[6] & 0xff);
357 X509CertificateStructure last_cert = null;
358 X509CertificateStructure this_cert = null;
360 for(int i=0; i<numcertbytes;) {
361 int certlen = ((rec[7 + i] & 0xff) << 16) | ((rec[7 + i + 1] & 0xff) << 8) | (rec[7 + i + 2] & 0xff);
363 DERInputStream dIn = new DERInputStream(new ByteArrayInputStream(rec, 7 + i + 3, certlen));
364 this_cert = new X509CertificateStructure((DERSequence)dIn.readObject());
365 } catch (Exception e) {
366 SSLException t = new SSLException("error decoding server certificate: " + e);
367 t.fillInStackTrace();
371 if (server_cert == null) {
372 server_cert = this_cert;
373 TBSCertificateStructure tbs = server_cert.getTBSCertificate();
375 // gross hack to extract the Common Name so we can compare it to the server hostname
376 String CN = tbs.getSubject().toString() + " ";
377 boolean good = false;
378 for(int j=0; j<CN.length() - 3; j++)
379 if (CN.substring(j, j+3).equals("CN=")) {
381 CN = CN.substring(j+3, CN.indexOf(' ', j+3));
385 if (!good) throw new SSLException("server certificate does not seem to have a CN: " + CN);
386 if (!ignoreUntrustedCert && !CN.equalsIgnoreCase(hostname))
387 throw new SSLException("connecting to host " + hostname + " but server certificate was issued for " + CN);
389 SimpleDateFormat dateF = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss-z");
391 // the following idiocy is a result of the brokenness of the GNU Classpath's SimpleDateFormat
392 String s = tbs.getStartDate().getTime();
393 s = s.substring(0, 4) + "-" + s.substring(4, 6) + "-" + s.substring(6, 8) + "-" +
394 s.substring(8, 10) + "-" + s.substring(10, 12) + "-" +
395 s.substring(12, 14) + "-" + s.substring(14);
397 Date startDate = dateF.parse(s, new ParsePosition(0));
399 s = tbs.getEndDate().getTime();
400 s = s.substring(2, 4) + "-" + s.substring(4, 6) + "-" + s.substring(0, 2) + "-" + s.substring(6, 8) + "-" +
401 s.substring(8, 10) + "-" + s.substring(10, 12) + "-" + s.substring(12);
402 Date endDate = dateF.parse(s, new ParsePosition(0));
404 Date now = new Date();
405 if (!ignoreUntrustedCert && now.after(endDate))
406 throw new SSLException("server certificate expired on " + endDate);
407 if (!ignoreUntrustedCert && now.before(startDate))
408 throw new SSLException("server certificate will not be valid until " + startDate);
410 Log.info(this, "server cert (name, validity dates) checks out okay");
414 // don't check the top cert since some very old root certs lack a BasicConstraints field.
415 if (certlen + 3 + i < numcertbytes) {
416 // defend against Mike Benham's attack
417 X509Extension basicConstraints = this_cert.getTBSCertificate().getExtensions().getExtension(X509Extensions.BasicConstraints);
418 if (basicConstraints == null) throw new SSLException("certificate did not contain a basic constraints block");
419 DERInputStream dis = new DERInputStream(new ByteArrayInputStream(basicConstraints.getValue().getOctets()));
420 BasicConstraints bc = new BasicConstraints((DERSequence)dis.readObject());
421 if (!bc.isCA()) throw new SSLException("non-CA certificate used for signing");
424 if (!isSignedBy(last_cert, this_cert.getSubjectPublicKeyInfo()))
425 throw new SSLException("the server sent a broken chain of certificates");
428 last_cert = this_cert;
432 if (Log.on) Log.info(this, " Certificate (" + numcerts + " certificates)");
434 if (ignoreUntrustedCert) break;
436 boolean good = false;
438 // pass 1 -- only check CA's whose subject is a partial match
439 String subject = this_cert.getSubject().toString();
440 for(int i=0; i<trusted_CA_public_keys.length; i++) {
441 if (subject.indexOf(trusted_CA_public_key_identifiers[i]) != -1 && isSignedBy(this_cert, trusted_CA_public_keys[i])) {
442 if (Log.on) Log.info(this, "pass 1: server cert was signed by trusted CA " + i);
448 // pass 2 -- try all certs
450 for(int i=0; i<trusted_CA_public_keys.length; i++) {
451 if (isSignedBy(this_cert, trusted_CA_public_keys[i])) {
452 if (Log.on) Log.info(this, "pass 2: server cert was signed by trusted CA " + i);
458 if (!good) throw new SSLException("server cert was not signed by a trusted CA");
462 if (Log.on) Log.info(this, "got ServerKeyExchange");
463 serverKeyExchange = rec;
467 if (Log.on) Log.info(this, "got Request for Client Certificates");
468 cert_requested = true;
471 case 14: if (Log.on) Log.info(this, " ServerHelloDone"); return;
472 default: throw new SSLException("unknown handshake of type " + rec[0]);
477 public void readServerFinished() throws IOException {
479 byte[] rec = readHandshake();
480 if (rec[0] != 20) throw new SSLException("expecting server Finished message, but got message of type " + rec[0]);
482 byte[] expectedFinished = concat(new byte[][] {
483 md5(new byte[][] { master_secret, pad2,
484 md5(new byte[][] { handshakes, new byte[] { (byte)0x53, (byte)0x52, (byte)0x56, (byte)0x52 },
485 master_secret, pad1 }) }),
486 sha(new byte[][] { master_secret, pad2_sha,
487 sha(new byte[][] { handshakes, new byte[] { (byte)0x53, (byte)0x52, (byte)0x56, (byte)0x52 },
488 master_secret, pad1_sha } ) } ) } );
490 for(int i=0; i<expectedFinished.length; i++)
491 if (expectedFinished[i] != rec[i + 4])
492 throw new SSLException("server Finished message mismatch!");
494 if (Log.on) Log.info(this, "server finished message checked out okay!");
499 class SSLOutputStream extends OutputStream {
501 /** the underlying outputstream */
502 DataOutputStream raw;
504 /** the sequence number for sending */
505 public long seq_num = 0;
507 /** the encryption engine for sending */
508 RC4Engine rc4 = null;
510 public SSLOutputStream(OutputStream raw) { this.raw = new DataOutputStream(raw); }
511 public void flush() throws IOException { raw.flush(); }
512 public void write(int b) throws IOException { write(new byte[] { (byte)b }, 0, 1); }
513 public void write(byte[] b, int off, int len) throws IOException { write(b, off, len, (byte)23); }
514 public void close() throws IOException {
515 write(new byte[] { 0x1, 0x0 }, 0, 2, (byte)21);
519 /** writes a single SSL Record */
520 public void write(byte[] payload, int off, int len, byte type) throws IOException {
522 // largest permissible frame is 2^14 octets
524 write(payload, off, 1 << 14, type);
525 write(payload, off + 1 << 14, len - 1 << 14, type);
530 raw.writeShort(0x0300);
534 raw.write(payload, off, len);
537 byte[] MAC = computeMAC(type, payload, off, len, client_write_MAC_secret, seq_num);
538 byte[] encryptedPayload = new byte[MAC.length + len];
539 rc4.processBytes(payload, off, len, encryptedPayload, 0);
540 rc4.processBytes(MAC, 0, MAC.length, encryptedPayload, len);
541 raw.writeShort(encryptedPayload.length);
542 raw.write(encryptedPayload);
549 /** tacks a handshake header onto payload before sending it */
550 public void writeHandshake(int type, byte[] payload) throws IOException {
551 byte[] real_payload = new byte[payload.length + 4];
552 System.arraycopy(payload, 0, real_payload, 4, payload.length);
553 real_payload[0] = (byte)(type & 0xFF);
554 intToBytes(payload.length, real_payload, 1, 3);
555 handshakes = concat(new byte[][] { handshakes, real_payload });
556 write(real_payload, 0, real_payload.length, (byte)22);
559 public void sendClientHandshakes() throws IOException {
561 if (Log.on) Log.info(this, "shaking hands");
562 if (cert_requested) {
563 if (Log.on) Log.info(this, "telling the server we have no certificates");
564 writeHandshake(11, new byte[] { 0x0, 0x0, 0x0 });
567 // generate the premaster secret
568 byte[] pre_master_secret = new byte[48];
569 pre_master_secret[0] = 0x03; // first two bytes of premaster secret are our version number
570 pre_master_secret[1] = 0x00;
571 getRandomBytes(pre_master_secret, 2, pre_master_secret.length - 2);
573 // encrypt and send the pre_master_secret
575 byte[] encrypted_pre_master_secret;
577 SubjectPublicKeyInfo pki = server_cert.getSubjectPublicKeyInfo();
578 RSAPublicKeyStructure rsa_pks = new RSAPublicKeyStructure((DERSequence)pki.getPublicKey());
579 BigInteger modulus = rsa_pks.getModulus();
580 BigInteger exponent = rsa_pks.getPublicExponent();
582 if (serverKeyExchange != null) {
584 AsymmetricBlockCipher rsa = /*new PKCS1(*/new RSAEngine()/*)*/;
585 rsa.init(false, new RSAKeyParameters(false, modulus, exponent));
587 int modulus_size = ((serverKeyExchange[4] & 0xff) << 8) | (serverKeyExchange[5] & 0xff);
588 byte[] b_modulus = new byte[modulus_size];
589 System.arraycopy(serverKeyExchange, 6, b_modulus, 0, modulus_size);
590 modulus = new BigInteger(1, b_modulus);
592 int exponent_size = ((serverKeyExchange[6 + modulus_size] & 0xff) << 8) | (serverKeyExchange[7 + modulus_size] & 0xff);
593 byte[] b_exponent = new byte[exponent_size];
594 System.arraycopy(serverKeyExchange, 8 + modulus_size, b_exponent, 0, exponent_size);
595 exponent = new BigInteger(1, b_exponent);
597 byte[] server_params = new byte[modulus_size + exponent_size + 4];
598 System.arraycopy(serverKeyExchange, 4, server_params, 0, server_params.length);
600 byte[] expectedSignature = concat(new byte[][] { md5(new byte[][] { client_random, server_random, server_params } ),
601 sha(new byte[][] { client_random, server_random, server_params } ) } );
603 byte[] recievedSignature = rsa.processBlock(serverKeyExchange, 6 + server_params.length,
604 serverKeyExchange.length - 6 - server_params.length);
606 for(int i=0; i<expectedSignature.length; i++)
607 if (expectedSignature[i] != recievedSignature[i])
608 throw new SSLException("ServerKeyExchange message had invalid signature " + i);
610 if (Log.on) Log.info(this, "ServerKeyExchange successfully processed");
613 AsymmetricBlockCipher rsa =/* new PKCS1(*/new RSAEngine()/*)*/;
614 rsa.init(true, new RSAKeyParameters(false, modulus, exponent));
616 encrypted_pre_master_secret = rsa.processBlock(pre_master_secret, 0, pre_master_secret.length);
617 writeHandshake(16, encrypted_pre_master_secret);
619 } catch (Exception e) {
620 SSLException t = new SSLException("exception encrypting premaster secret");
621 t.fillInStackTrace();
626 if (Log.on) Log.info(this, "Handshake complete; sending ChangeCipherSpec");
627 write(new byte[] { 0x01 }, 0, 1, (byte)20);
630 // compute master_secret
631 master_secret = concat(new byte[][] {
632 md5(new byte[][] { pre_master_secret,
633 sha(new byte[][] { new byte[] { 0x41 }, pre_master_secret, client_random, server_random })}),
634 md5(new byte[][] { pre_master_secret,
635 sha(new byte[][] { new byte[] { 0x42, 0x42 }, pre_master_secret, client_random, server_random })}),
636 md5(new byte[][] { pre_master_secret,
637 sha(new byte[][] { new byte[] { 0x43, 0x43, 0x43 }, pre_master_secret, client_random, server_random })})
640 // construct the key material
641 byte[] key_material = new byte[] { };
642 for(int i=0; key_material.length < 72; i++) {
643 byte[] crap = new byte[i + 1];
644 for(int j=0; j<crap.length; j++) crap[j] = (byte)(((byte)0x41) + ((byte)i));
645 key_material = concat(new byte[][] { key_material,
646 md5(new byte[][] { master_secret,
647 sha(new byte[][] { crap, master_secret, server_random, client_random }) }) });
650 client_write_key = new byte[export ? 5 : 16];
651 server_write_key = new byte[export ? 5 : 16];
653 System.arraycopy(key_material, 0, client_write_MAC_secret, 0, 16);
654 System.arraycopy(key_material, 16, server_write_MAC_secret, 0, 16);
655 System.arraycopy(key_material, 32, client_write_key, 0, export ? 5 : 16);
656 System.arraycopy(key_material, export ? 37 : 48, server_write_key, 0, export ? 5 : 16);
659 // see SSLv3 spec, 6.2.2 for explanation
660 byte[] client_untrimmed = md5(new byte[][] { concat(new byte[][] { client_write_key, client_random, server_random } ) });
661 byte[] server_untrimmed = md5(new byte[][] { concat(new byte[][] { server_write_key, server_random, client_random } ) });
662 client_write_key = new byte[16];
663 server_write_key = new byte[16];
664 System.arraycopy(client_untrimmed, 0, client_write_key, 0, 16);
665 System.arraycopy(server_untrimmed, 0, server_write_key, 0, 16);
668 rc4 = new RC4Engine();
669 rc4.init(true, new KeyParameter(client_write_key));
670 is.rc4 = new RC4Engine();
671 is.rc4.init(false, new KeyParameter(server_write_key));
674 writeHandshake(20, concat(new byte[][] {
675 md5(new byte[][] { master_secret, pad2,
676 md5(new byte[][] { handshakes, new byte[] { (byte)0x43, (byte)0x4C, (byte)0x4E, (byte)0x54 },
677 master_secret, pad1 }) }),
678 sha(new byte[][] { master_secret, pad2_sha,
679 sha(new byte[][] { handshakes, new byte[] { (byte)0x43, (byte)0x4C, (byte)0x4E, (byte)0x54 },
680 master_secret, pad1_sha } ) })
683 if (Log.on) Log.info(this, "wrote Finished message");
687 public void writeClientHello() throws IOException {
689 if (Log.on) Log.info(this, "sending ClientHello");
690 int unixtime = (int)(System.currentTimeMillis() / (long)1000);
692 byte[] out = new byte[] {
693 0x03, 0x00, // client version (SSLv3.0)
695 // space for random bytes
696 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
697 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
700 0x0, // empty vector for sessionid
701 0x0, 0x4, 0x0, 0x4, 0x0, 0x3, // we support two ciphersuites: SSL_RSA_WITH_RC4_128_MD5 and SSL_RSA_EXPORT_WITH_RC4_40_MD5
702 0x1, 0x0 // we only support one compression method: none
705 // don't need to use secure random here since it's sent in the clear
706 Random rand = new Random(System.currentTimeMillis());
707 rand.nextBytes(client_random);
708 intToBytes(unixtime, client_random, 0, 4);
709 System.arraycopy(client_random, 0, out, 2, client_random.length);
711 writeHandshake(1, out);
716 // Static Helpers ////////////////////////////////////////////////////////////////////
718 /** copy the least significant num bytes of val into byte array b, startint at offset */
719 public static void intToBytes(long val, byte[] b, int offset, int num) {
720 for(int i=0; i<num; i++)
721 b[offset + num - i - 1] = (byte)((val & (0xFFL << (i * 8))) >> (i * 8));
724 /** fills b with random bytes */
725 public static synchronized void getRandomBytes(byte[] b, int offset, int len) {
726 MD5Digest md5 = new MD5Digest();
727 byte[] b2 = new byte[16];
730 md5.update(randpool, 0, randpool.length);
731 intToBytes(randcnt++, b2, 0, 8);
732 md5.update(b2, 0, 8);
734 int n = len < 16 ? len : 16;
735 System.arraycopy(b2, 0, b, offset, n);
741 public static byte[] computeMAC(byte type, byte[] payload, int off, int len, byte[] MAC_secret, long seq_num) {
742 byte[] MAC = new byte[16];
743 MD5Digest md5 = new MD5Digest();
744 md5.update(MAC_secret, 0, MAC_secret.length);
745 md5.update(pad1, 0, pad1.length);
747 byte[] b = new byte[11];
748 intToBytes(seq_num, b, 0, 8);
750 intToBytes(len, b, 9, 2);
751 md5.update(b, 0, b.length);
753 md5.update(payload, off, len);
756 md5.update(MAC_secret, 0, MAC_secret.length);
757 md5.update(pad2, 0, pad2.length);
758 md5.update(MAC, 0, MAC.length);
764 public static byte[] concat(byte[][] inputs) {
766 for(int i=0; i<inputs.length; i++) total += inputs[i].length;
767 byte[] ret = new byte[total];
769 for(int i=0; i<inputs.length; i++) {
770 System.arraycopy(inputs[i], 0, ret, pos, inputs[i].length);
771 pos += inputs[i].length;
776 SHA1Digest master_sha1 = new SHA1Digest();
777 public byte[] sha(byte[][] inputs) {
779 for(int i=0; i<inputs.length; i++) master_sha1.update(inputs[i], 0, inputs[i].length);
780 byte[] ret = new byte[master_sha1.getDigestSize()];
781 master_sha1.doFinal(ret, 0);
785 MD5Digest master_md5 = new MD5Digest();
786 public byte[] md5(byte[][] inputs) {
788 for(int i=0; i<inputs.length; i++) master_md5.update(inputs[i], 0, inputs[i].length);
789 byte[] ret = new byte[master_md5.getDigestSize()];
790 master_md5.doFinal(ret, 0);
794 // FEATURE: improve error reporting in here
795 /** returns true iff certificate "signee" is signed by public key "signer" */
796 public static boolean isSignedBy(X509CertificateStructure signee, SubjectPublicKeyInfo signer) throws SSLException {
800 String signature_algorithm_oid = signee.getSignatureAlgorithm().getObjectId().getId();
801 if (signature_algorithm_oid.equals("1.2.840.113549.1.1.4")) hash = new MD5Digest();
802 else if (signature_algorithm_oid.equals("1.2.840.113549.1.1.2")) hash = new MD2Digest();
803 else if (signature_algorithm_oid.equals("1.2.840.113549.1.1.5")) hash = new SHA1Digest();
804 else throw new SSLException("unsupported signing algorithm: " + signature_algorithm_oid);
807 // decrypt the signature using the signer's public key
808 byte[] ED = signee.getSignature().getBytes();
809 SubjectPublicKeyInfo pki = signer;
810 RSAPublicKeyStructure rsa_pks = new RSAPublicKeyStructure((DERSequence)pki.getPublicKey());
811 BigInteger modulus = rsa_pks.getModulus();
812 BigInteger exponent = rsa_pks.getPublicExponent();
813 AsymmetricBlockCipher rsa = /*new PKCS1(*/new RSAEngine()/*)*/;
814 rsa.init(false, new RSAKeyParameters(false, modulus, exponent));
816 // Decode the embedded octet string
817 byte[] D = rsa.processBlock(ED, 0, ED.length);
818 BERInputStream beris = new BERInputStream(new ByteArrayInputStream(D));
819 DERObject derob = beris.readObject();
820 DERSequence dercs = (DERSequence)derob;
821 DEROctetString deros = (DEROctetString)dercs.getObjectAt(1);
822 byte[] MD = deros.getOctets();
824 // generate our own hash
825 ByteArrayOutputStream baos = new ByteArrayOutputStream();
826 DEROutputStream dos = new DEROutputStream(baos);
827 dos.writeObject(signee.getTBSCertificate());
829 byte[] b = baos.toByteArray();
830 hash.update(b, 0, b.length);
831 byte[] md_out = new byte[MD.length];
832 hash.doFinal(md_out, 0);
834 // compare our hash to the signed hash
835 for(int j=0; j<MD.length; j++) if (md_out[j] != MD[j]) return false;
838 } catch (Exception e) {
844 // Embedded Trusted Public Keys //////////////////////////////////////////////
846 /** base64-encoded sequence of DER-encoded PKCS7 certs for all the "trusted root CA's" included with IE5.5 */
847 static String[] base64_encoded_trusted_CA_public_keys = new String[] {
849 "CN=ABA.ECOM Root CA",
850 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdMR4HlVQwcITMsFQgDiDYNGPe" +
851 "STurYG0w1ZvT7BzkNnAYohqO+8zNCizLBVllOEZgUA2kRJgNhUCqUlhpTtY1b/cGyjoRnS" +
852 "eL5oKkReL8/MGF5HvDqxRj0e8LksNF+MfEwIKZ1AVes8fYPetfD3ioMOoUy0OqWzX1oil+" +
853 "wZm8EFaP3mt6mRlCzkeEgkGiUZOuuVnDkKis9CsvAc1V/7a+1oVns5LHI4sO6TqdN7dzzr" +
854 "cQOpOEoWbIkqytozE3nCVYztnLvyy1sQ+C5hNcYpTCrQKmPRZVm0+M359ACEtldChZ0yqP" +
855 "kqVPv/eEG8vXEo9LuQvP+WNATjRZ6hRihAgQIDAQAB",
858 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCws2enlrV2g+kWA9kaoHbVdOecBdJRP9" +
859 "tPGaGoOU7LJH1hxB5qIK4Pgd7quDn9Gx9rNkDtTSEl8qPZoVHYbMAblvjUQpTUp84bj9NU" +
860 "JqKE7zKFr0o/8TI2rz3mOifrA8IlfvRhK62KGkvmmzZo1C/l0oiU3Baq2sIVTGzD4RmRyQ" +
863 "CN=Xcert EZ by DST",
864 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArVQY3rS/963odKrti3yPwtR1Gt" +
865 "WEubZi/Inv5JdhkvsduOFaRzSengYi+9PqOMu4iwf3GqAXdwdaMBzUKTgg1ydA2FCTQ7/S" +
866 "GKIpdgVyqmu2aZireR4cZfVqi/zFFqqictpg7U5uGSV6Ch0w41CbQjxE66GwIB7bAn7+PR" +
867 "+/0ACK20B2philFadXtlLCAReYd4+KgcYatGoq5q+p1gCsz9gVSXzbG6H+gfqH+dOQwQLA" +
868 "+dBC6ZFoJV/Gv4c56ZUAYCi/gyzA51621zYW52CHdujnJ7IlDYt65aod5VnNzgsOb8bInO" +
869 "MQ2YU507eb+sa6fHTSXXVWq3SkolG/UnzucQIDAQAB",
871 "CN=Certiposte Classe A Personne",
872 "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQAox3xaJSN48rMAR0Biy2+MQlCfnl" +
873 "7UXA5lC1hWlSvjRtBhNuAtRpuCy5Hu0pV8mpKvBAp+pp/g17HDRfmYQRs5redW19m2f867" +
874 "OS4sO8+2cwODzhNdMmpjottb+Esz6FBsy6gX7J6TuWwGSyYLdx6e+eWMiTfS0bv9qYwrLJ" +
875 "wQMdhLjM23cX44LCnjF7JP6FK245I80v3hAtphEHTSGvPI0dFmB1/EhGNpva5s3GUjHLf7" +
876 "98YTLoN+P6nlCyBtAQo34lzait4icOkN4HQ9xOtxm2Eq4g0Ui0xGN0wm0mjWVsNXqqJgN6" +
877 "9fnaCzgILmQypMgAAJUNmoanNtA/5ec5LlAgMBAAE=",
879 "CN=Certiposte Serveur",
880 "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQA+p3gzOJHiylaV0ZFGsiPcpVZ/D8" +
881 "eXuOKekS4oFi6O80e2XIPE8Ob+ZxqTZH1ACdgdaADs1BHu2GOJAyPphF/HVQ5K4nK7KcFV" +
882 "ZHao45LN9/ZuQlYYUjOJ+YAUqBlRfsd3v3qoMcB9F25DTtVmyQU+S+Ll4lUbdKpRHarMmB" +
883 "F3pOvbKg4nx9XNSOzcfk5J50HNmQvRS14YGw06CpstmznHQAzQdgd8fI9+XHKOh9W+8qa5" +
884 "3r/dnxJ5R3zFyZdARgCS0xNak0+dfthfTMFdSEnZLZg8/MynhyHwPo5yfVk4NhYaDEi+of" +
885 "LVPqgWDCBZz84PM4M9rav1/93X/WkIiADvAgMBAAE=",
887 "OU=Certisign - Autoridade Certificadora - AC2",
888 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5MMyl65DWVpRnM4mDbUa+cJeTF04KJ3" +
889 "DOycXyxdIt0RGcdzJsdNOSb/rp1bhhmqpMEz41OvDuCTbZ0Zcxx16sQUm/SG1OIFPJe2qj" +
890 "ljFrsm6ozy9yTAatMs9aCPN9EJyqu7pz+fPwuCRvqGW2Iv4FWxBVRMIDHa3RIswIbfuMyw" +
893 "OU=Certisign - Autoridade Certificadora - AC4",
894 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDsg9TMg5A/X+y+wenQx1hGWR/xk0qyFx" +
895 "MLzymZqwRFM+PRXr68jiV3Yt2bkpsxCkBFedXys91suUD9mH9Aoi3pspO9S9XB3unR+nH3" +
896 "P0G89BSvzWvIOUqdYGW0hNBqQeljrptp6rlGHNsYCDtiTN5B156GfxNyEdTc6t5gpbvdGw" +
899 "OU=Certisign Autoridade Certificadora AC1S",
900 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwwJXro8VB+JtvcWOOkRFX+QPHaJoanG" +
901 "Hwww8Ml2KIfiYBNX398W9PF5WqfvK7vO/idnNhlTZRgz6E6D+6VzY3lBNskmQflA3rVC9R" +
902 "WuUoXvCShufkbSF6XzcL51u9LQKogfk/yxTIvKTF49HLN9yr5Yeq8guYLnrPzB7Cf+j9AQ" +
905 "OU=Certisign Autoridade Certificadora AC3S",
906 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOZE7Wz658mCeY7yjvujTDNRqd0mYecf" +
907 "Hkli0nFzmQRY8t7+bVR6nhg4F8Pihx+oC7XfhDaxkQwZhvFZ4trklkROyEGmlZFleyPZLY" +
908 "Zku/ma1DGMc4yYuOLAQus0trk/adH4SyzeYAwr42pbxZtZ+LGSD/5agopFW2irayxddE4w" +
911 "O=Certplus, CN=Class 1 Primary CA",
912 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw2spyC7HrnxSBemTiVYKWnnJzN" +
913 "wl74eKLQXYgRcEGzpF+HkODUnUgUHIq0X7dcgV8uLQvNlhbISkExmn2fnySdxMD8Z9V7QT" +
914 "3B4JcSk2nYBY9BvYiRTr09KTSyrxd+dqZb0Z5ar9DEpj4cKZtA8EtlobNjw3PL/F5V7xX1" +
915 "cOH8f9LOfkb2qbYpY5EZtm8Cy2UtzhJ//bbf7rq2MUHWOIY+IWDPkgVA+b3RVqdoNPvSeL" +
916 "U6Y30ofyR1BSO2bp0XgaG7I7afBZPDhb0SpMM14Oylal7S1bgoNN1jhOila2ai8kaxIwpi" +
917 "rerwy7qkQSHBPFZQ/j/dgaMUvkPwx8RegWMwIDAQAB",
919 "O=Certplus, CN=Class 2 Primary CA",
920 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3FCW0BL4NdIIeHq2UnD9b+7PuR" +
921 "HLXXfh7Ol+BI3WzG9zQ1dgrDMKROwDXxyAJJHlqJFWEoL34Cv0265hLokQjWtsurMCvdU2" +
922 "xUg3I+LwWjdSMxcS4tFgTb4vQRHj9hclDIuRwBuZe5lWDa/u0rxHV+N5SXs0iSckhN6x7O" +
923 "lYTv5O31q+Qa2sCMUYDu/SU+5s0J0SARON3IBi95WpRIhKcU5gVZ7bIxl5VgcMP2MLXLDi" +
924 "vn4V/JQzWEE4dMThj4vfJqwftYs7t0NZa7Akpm2Qi8Ry6l0zmLfL3l5775TxGz7KySHBxZ" +
925 "gCqqL2W3eb9X6WVTQcZ2nA8ULjR6z8KBxmVQIDAQAB",
927 "O=Certplus, CN=Class 3 Primary CA",
928 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt5QwbtBM2X5eYOVvuybKUm9rbI" +
929 "WZpQvvABpvG01YtRgH+t17+MssUt38nLiNUum5sgt89Y9bmUgJWN7NSJWGJYkFNCcwC1e2" +
930 "DHdjKctsqj65mVESDZhwdkdM+UmWIgj5a+qqADajFaccHp+Mylp5eyHaiR9jfnmSUAkEKK" +
931 "3O420ESUqZsT9FCXhYIO+N/oDIBO0pLKBYjYQCJZc/oBPXe4sj45+4x7hCQDgbkkq9SpRV" +
932 "x1YVDYF3zJ+iN4krW4UNi3f4xIv7EMuUx+kaVhKXZhTEu9d9bQIbv3FiJhjpSYr6o97hhK" +
933 "2AykriIoxqCGGDsiLHCYg4Vl3RMavwCZ8TWQIDAQAB",
935 "CN=Autoridad Certificadora de la Asociacion Nacional del Notariado Mexicano",
936 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7tlrVYRxJvaOrUG71tLeY+ryP2" +
937 "XyOxPBrlEm9L94j8ZMSay/Qd71KMco55/XgOXU7iMrk5U9yY9q9coA6RDHiIIabqNf8DRS" +
938 "ISVoKPiV8ICVoiyxP2r2KNbihP0WZ5wluXXb5cZZA7SrQgeI1VxIRaIJA8muZ5KoolPHyq" +
939 "t+mhKVWgVXjRBklicRsOYyMFvNPQygGxMtuxqr3TnOkmuiBNQTX213Z1Q5qHtpisZfeMoH" +
940 "GGlu+cDT0IqOrx4waO742KhmDIR9I2qJPGJNFHSs25uc/LCD/gcw8factEjI5jpCJQko91" +
941 "bCsdejmHcCh+qKwV3axIonB4VeSExVKEDtCQIDAQAB",
943 "O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
944 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhA" +
945 "wL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lw" +
946 "dd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpw" +
949 "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
950 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhA" +
951 "wL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lw" +
952 "dd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpw" +
955 "C=FR, O=Certplus, CN=Class 3P Primary CA",
956 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqzf/62CbQXhp9UlYsN4fcWmmK+" +
957 "OuUMapvJPpIL7kxBOCVu/wQzIJypt1A498T+HgT3aeC61kehQ6mp2/LxYLZRyp7py84xpl" +
958 "y0+F6pJWdWbWVUDv+8zWOD+rHO9CjRmJ9reVhsKnHen3KfEq2WV5/Cv1jsoad36e6Kz5Zr" +
959 "9F++gTnV+2c+V9e477EnRdHwZehRumXhhEALq8027RUg4GrevutbTBu7zrOA9IIpHHb9K4" +
960 "cju6f8CNbLe8R3MhKoX/rNYoohnVl2o6uaxtRezmTcPbqF3FXYKYrEpaquYrCAwQdLxi9j" +
961 "pJBGbYURwmpth1n5y/rmBRPVy8ok97iWfNUwIDAQAB",
963 "C=FR, O=Certplus, CN=Class 3TS Primary CA",
964 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvWWaI0MAPPklAUOYW0Y0N2c39F" +
965 "tXjqPezYwvQbMVPeWYi/LMXKfHrzXHs6dPxxApV+kDiYNyBnZSwXACN0Dt8M6LsbGJrAKo" +
966 "W93c1UNFBtwotulRG2ru83tIxZ0Rro2mcpPAJUKRqD5G4mhMgUCwQtN6vntH0kdQDKQSps" +
967 "rkEtDAfDo8AanKApbeglrF+xm6PJzYD3QfmBiulFAyB1IQEUpL7FhVLNSeS5R7BdJy3wbw" +
968 "jcsInuTutEStgvEbYWrxs/gWMTZCJLqQv7V+YW7CWQxUebRMiCgezBvfhIsjyL6vB/KRst" +
969 "qNyoxffCg8fIlsBlm9Ps7FgtNqyaxoVe7FrwIDAQAB",
971 "C=US, O=RSA Data Security, Inc., OU=Commercial Certification Authority",
972 "MIGbMA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AKT7gWJ7zhAn3ej3vmxuxnCZ27jVBQNpKI" +
973 "Kccn+WP47srCmSP4oU+EJ2vr1dA7mQ1NC8BrJRM1/Ewr+2i4+ZtmIiYN3b3yCCtMqiLy1Q" +
974 "7ZQy3uBVjdRo4uBM0s0FFi6VZlxhUjgeUaiCocTvJekK5osrjjFm2fjZ/b07adnrAgMBAA" +
977 "C=DE, O=Deutsche Telekom AG, OU=T-TeleSec Trust Center, CN=Deutsche Telekom Root CA 1",
978 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQ3ZsMoBdERA+vIUBzZ1bwPmloEbrZN/" +
979 "KBrsMkrGmhzfymGFVW/4ufMsHb53gsOdtggUGl79PNgI0YPOJSDAuf92Se5aDwuGFi9L/g" +
980 "o9pYK/0VBGu9Op58nfI92OSVw+xOwvFlqwxL7EeCW+LhUHXY9mG0GFztM6BLHoP7T4S8eQ" +
983 "C=DE, O=Deutsche Telekom AG, OU=T-TeleSec Trust Center, CN=Deutsche Telekom Root CA 2",
984 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqwujNeCLKRSxFIWvPBDkOW81XU" +
985 "qu3ephjZVJ9G9koxpgZqSpQCKE2dSl5XiTDmgBrblNXDrO07ioQkDfz6O6gllqkhusHJra" +
986 "CCslJ/lpI0fx4Ossepv1EwLQfjR8wp48AFmr9doM9TI8K6xQ2tbD3oOUyqgMmTIOCEhWW2" +
987 "r72uFYWAFJX3JBPBUGAY5draq4k7TNnuun6GotUjTbOu9cdVHa2/Mx+e5xmDLEVBVEDPmb" +
988 "Ve2t3xgIoKOGiknuUwWPGUzV3lh5m9JqHEKrxdWnz2gPluThYZh2YciRfNY+AOKRUIfhnQ" +
989 "rmrZfSHcY6fcu82gM01Y5bAfVqB7cWtm5KfwIDAQAB",
991 "C=US, O=Digital Signature Trust Co., OU=DST (ANX Network) CA",
992 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC0SBGAWKDVpZkP9jcsRLZu0XzzKmueEb" +
993 "aIIwRccSWeahJ3EW6/aDllqPay9qIYsokVoGe3eowiSGv2hDQftsr3G3LL8ltI04ceInYT" +
994 "BLSsbJZ/5w4IyTJRMC3VgOghZ7rzXggkLAdZnZAa7kbJtaQelrRBkdR/0o04JrBvQ24JfQ" +
997 "OU=National Retail Federation, CN=DST (NRF) RootCA",
998 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2aybd/pQ08zcuUCsuXJqAIcj/A" +
999 "+WIdAmr+TitV/606Z9ITAuzBeCj5h0/Gekpt+Il6JCKfWn2xGT+14jMMKqvCLnQRvl7SXe" +
1000 "yD/b3ldFeEBGg7LVGj3fD0Vt1WMCddgvxm6rlZF0Nw3LTQlc0dRbOtrdDshrmdjVOczfhV" +
1001 "XEklMCo+H3gMlwo9rcM8R/okcIHDWWH6EDHDCD9MTM/5jDsEZEosC/rdvSgfZMmCynXiTz" +
1002 "hspj1bp98JrAStAbWO7sqWfPaQJsIsBgLCzRyCDqyC373Zy7y1FM3OdXBDtUmxGlMnTsdA" +
1003 "HzkBVbL3wsk2W5Zme0gYg15Z6RGH+BqEHIywIDAQAB",
1005 "OU=United Parcel Service, CN=DST (UPS) RootCA",
1006 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7xfsrynm2SsnwNt7JJ9m9ASjwq" +
1007 "0KyrDNhCuqN/OAoWDvQo/lXXdfV0JU3SvbYbJxXpN7b1/rJCvnpPLr8XOzC431Wdcy36yQ" +
1008 "jk4xuiVNtgym8eWvDOHlb1IDFcHfvn5KpqYYRnA/76dNqNz1dNlhekA8oZQo6sKUiMs3FQ" +
1009 "UZPJViuhwt+yiM0ciekjxbEVQ7eNlHO5stSuY+e2vf9PYFzyj2upg2AJ48N4UKnN63pIXF" +
1010 "Y/23YhRtFx7MioCFQjIRsCHinXfJgBZBnuvlFIl/t8O8T8Gfh5uW7GP2+ZBWDpWjIwqMZN" +
1011 "qbuxx3sExd5sjo9X15LVckP8zjPSyYzxKfFwIDAQAB",
1013 "CN=Autoridad Certificadora del Colegio Nacional de Correduria Publica Mexicana",
1014 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmO0dhYH7/jd0viOAJ18bQX6856" +
1015 "WK2HNdlkjqq1iqfaUdz/4gCtnydQnts9X9+JMqGaleqLEU8tZChkFBXk/FVqeaokJvLihI" +
1016 "6i6r2cHZmvClnotdEWeaNzdTYGbxIv93d0fp3dwYRu4u3+LBluDqWN6H65OIaZmwPm52KU" +
1017 "Bhwyhmc3+sMXb0OM3WMo9zMhAVNNJ8RND8eQwAnX0P4+P3RPWedEknrRvXMshTrm8qsNe1" +
1018 "LRgsbjs6TUzb9Wi1L7AMkPk93HU2msLgv7uWiMJr7hjXTlA/V4tnaKS+AzNdWRI0if52yN" +
1019 "kVdgFUZP2s41DvEMjQ7l/sHd9PBZg8tBReAQIDAQAB",
1022 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0sYmtuelPcHEaNVQb1PFb0kTCb" +
1023 "ivLEiNFGqjF19a+dMudS/YKGLRky/8TdSrh+UIx5nnkj91vesltBXBmxk90kSN13QgbTcC" +
1024 "j2mTW4rEGZ30sg78Fmy5sQWSg9GFLGCUPkVVoNmrCCHmYOg7dPKZUFFo0AMtsYC+o9hSsE" +
1025 "TNQ0pwjliFleFOLNYtQW/WhOfImETKR9ssJKVpJs9ruCdiw/TJepIj7RNngq5FLkXlfnI/" +
1026 "hZ2UYhDmPJGhrXcA4BXs84SAcnqObmCXxyRZEDSDW+GlpGm2VzUceFnG0y86c2fulMoEEw" +
1027 "ViBnAjs/R87kXZZAtbSaqkQ84mxEQSbLjdeQIDAQAB",
1029 "OU=DSTCA X2, CN=DST RootCA X2",
1030 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3HXwjMB1lprAYh8m98ThmurgVn" +
1031 "Nbmc0BRKgIttWn2hoEGDmSSnijgcL1d3pQtHD/mqvGx8pug09CmPsmC9rcbdapmVVSZ+ko" +
1032 "A5Lc5bAFmg8V+WtZclby+jn8qmjuDx8Qgy/8nfoXlt2C4+ZFfcBLgEQf7SzghP2RXJJUaS" +
1033 "XlYmnc5e4AUr0zC611AoWnZFAtxRkZMMAm28nT/S6ZrVm1C03UQa6FSENZ3Leo4qLew4/X" +
1034 "uKFipmhQUuTPMaeUhdqfRjIXVuXy62Y9Ev9D25jvd8/LgY00scZQSibR5D5BUK9sriI0Lt" +
1035 "VrboO6ebh2ZUjaCSlkYyK5+0d2hYyGRMsJ2wIDAQAB",
1037 "C=US, O=Digital Signature Trust Co., OU=DST-Entrust GTI CA",
1038 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC2HfdLjQ8T4xL1Cf4GMg6vTEH1fdRHPS" +
1039 "oK34MF3t595gMW9lE6y0caSq1+xP0dtL50injdC4OOtIQTxPv4bSmuoeEPD0PjtV5gafqD" +
1040 "lPx55tx27dFEK479Erv+F3cXDIntp+9RfcTtOMM7o3r74k2gYLXy/RNl08bsP741nD0i7w" +
1043 "C=US, O=Digital Signature Trust Co., OU=DSTCA E1",
1044 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodG" +
1045 "BmE5gGHKlREmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+Lth" +
1046 "zfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQ" +
1049 "C=US, O=Digital Signature Trust Co., OU=DSTCA E2",
1050 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+S" +
1051 "SmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87e" +
1052 "ZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQ" +
1055 "CN=Entrust.net Certification Authority (2048)",
1056 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvw" +
1057 "tKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtL" +
1058 "A/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj/L24Sc" +
1059 "F2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLPKQP5L6RQstRIzgUy" +
1060 "VYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUiVBcAkCaTvA5JaJ" +
1061 "G/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQAB",
1063 "CN=Entrust.net Client Certification Authority",
1064 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/" +
1065 "Bo6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDe" +
1066 "g7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173iw" +
1069 "CN=Entrust.net Secure Server Certification Authority",
1070 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO" +
1071 "2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc" +
1072 "1lB5gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQw" +
1075 "C=US, O=Equifax, OU=Equifax Secure Certificate Authority",
1076 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBXbFYZwhi7qCaLR8IbZEUaJgKHv7aBG" +
1077 "8ThGIhw9F8zp8F4LgB8E407OKKlQRkrPFrU18Fs8tngL9CAo7+3QEJ7OEAFE/8+/AM3UO6" +
1078 "WyvhH4BwmRVXkxbxD5dqt8JoIxzMTVkwrFEeO68r1u5jRXvF2V9Q0uNQDzqI578U/eDHuQ" +
1081 "C=US, O=Equifax Secure Inc., CN=Equifax Secure eBusiness CA-1",
1082 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOLxm8F7d33pOpX1oNF080GgyY9CLZWd" +
1083 "TEaEbwtDXFhQMgxq9FpSFRRUHrFlg2Mm/iUGJk+f1RnKok2fSdgyqHCiHTEjg0bI0Ablqg" +
1084 "2ULuGiGV+VJMVVrFDzhPRvpt+C411h186+LwsHWAyKkTrL6I7zpuq18qOGICsBJ7/o+mAw" +
1087 "CN=Baltimore EZ by DST",
1088 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvMyzPUN5uEf5FbduJrFMkph57c" +
1089 "Vw8zrp1d0D9Co/YIyW5UcWAvc2svGeJoj1nkJlng+uf+PMsW4h9fGIInTWH7J3BDkyuke1" +
1090 "NcATXQFyowVDzE7aJpqHqGFj9GanwxVG6tHR6jDDu3Fqm8FDhsE5H8ZWYAIb/Ig6oJm7jN" +
1091 "d4YdBeV4+RO4CLbv/JZYEKObuQEyA1SD+l4b8twXGDhSDtIIfLtv4ZjATd7Sld3woSzolW" +
1092 "8h9aGTFYtv1jNurJI96nkZcnZXKZbMd6RMRfvpsfHsqeWBymqiNq4wYbkiTYVyIJUBWQRv" +
1093 "CDXraATBKBPWZvBFU6iGvQ71aHUKC51lUbnQIDAQAB",
1095 "C=US, O=Equifax Secure, OU=Equifax Secure eBusiness CA-2",
1096 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkOTmTHlIGGyg2+LKjKcXtjrIRvf7r57" +
1097 "R0wo//BefZnQa/Esg/DvLW0SSyEd7RcwmK1LEsmAkNHlBGsoOmRY1iaLuFGyBwMqpAzaaW" +
1098 "X8RxNz8E87dBJDkHGh4uYVigEgvlpd/Fq+o3ccwcyDc6uZdSp6zFaiSUTpx7z8Bq1t8hvQ" +
1101 "C=US, O=Equifax Secure Inc., CN=Equifax Secure Global eBusiness CA-1",
1102 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC65xeQAmWxNFU8ScJR1d+n0TeP0eeBc0" +
1103 "FSYJudoRcmeK3HsegmlDK13jONOi/b8pp6WnOYo1zp+4pzG1znw7+AbM2p9NYrwPf5mapj" +
1104 "orFHAg/U5FE6EjxsilpUhHDbwcWQz3JFy6hZwM0znT+jluuFMyEcPh4+YG52nGeFxcjDYQ" +
1107 "O=EUnet International, CN=EUnet International Root CA",
1108 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeQTvZQUmLKJxZFPdQaCh7TQhcZ/+FHg" +
1109 "umzzoyArB8fEqftokCIQxKmYvLZFF+eFq2XqlTt+/vx9+lIVmXTuIH5S18GdUqysgz05YQ" +
1110 "Lt2gAJ/9yuhhqVPKth0YPpwR4GPnKmdbyESV8BNVSLu+VbhnN83LABMN/E9pFGpRlOy8Jw" +
1113 "CN=FESTE, Public Notary Certs, EmailAddress=feste@feste.org",
1114 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhg/ObLsnn4cf0VAXNdkD+tLMTvucVXo" +
1115 "Ym6EB3GlU/0QMmjPqHX6TF+f61MonGf0GR2BVATnBS8PHa+GI1mV4clFNhzD5iwINdWNH4" +
1116 "SBFxbPewd+EYl7QHKDCRMcdPVPOEnsxZiUVtfrTJ245ClWbU3x4YTfylD9YahDnEyvK98w" +
1119 "CN=FESTE, Verified Certs",
1120 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqY58fOBqEBISzS5MZhKJ7YsOnqyzsYE" +
1121 "5VEeIEMicgNfkaeB8nZ6fggrAF6Capm4pEVr9LhFOjIqYOFlO5f68QyDMYVNnGTHzRW1ZS" +
1122 "U4amWz8T8sMB0jGhM1y8XeTcYjzKI5dPcPuBjrDZnq+T6raxJI0ELVFDPDjsJ0Nxh+g8xw" +
1125 "CN=First Data Digital Certificates Inc. Certification Authority",
1126 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDfHBQeCbm/pEByIJl5toQi9NeFksUEJO" +
1127 "gHLgLkF5UFN5V2Pfyx5Q+HDmK5LDCXJuELFWcAphXe6I3LlewCWFLAR2UzTFafCh8EwDdQ" +
1128 "gVe63/rya2fry9CAD9lXlRBlewZFWOuutF7jkxUrmby2KS/7Qp9HKy5M6zQoMpkO7/9voQ" +
1131 "C=ES, O=FNMT, OU=FNMT Clase 2 CA",
1132 "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCYP60ZNpM9Pv52QhT9NW/x+q0ieljjRt" +
1133 "Bdxlr5Yi2PMV7+tDD+UHSs1p0d4GLGSd0UEn1xC6wGwT/XBofgkInW5eMDsvInsZ8zyKpr" +
1134 "NkqjxD95QZ2JRi8rPmPUOFaRqh2xDUJ1TfOHTuMPTcy0bL9iE4fq0JuOtuL/GfSUCdWWYQ" +
1137 "CN=Belgacom E-Trust Primary CA",
1138 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq2bmz1U9qTcVB0HsEYWqLcYEH2mTjWG" +
1139 "4nVcKtzhew/PqSjQjwHHL/ssMx/uBqh5dMzENXpyh5OrWDXaQdavFqxT4UIh1ZBm/wpjF3" +
1140 "3LBJOObLDA/+qnI0iNooOiFa7nQrG6TbWxMWtXNfw66M0sA+PbDL8OyLhgvCwUQYWmOo1Q" +
1143 "C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA",
1144 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2g7mmY3Oo+NPin778YuDJWvqSB" +
1145 "/xKrC5lREEvfBj0eJnZs8c3c8bSCvujYmOmq8pgGWr6cctEsurHExwB6E9CjDNFY1P+N3U" +
1146 "jFAVHO9Q7sQu9/zpUvKRfeBt1TUwjl5Dc/JB6dVq47KJOlY5OG8GPIhpWypNxadUuGyJzJ" +
1147 "v5PMrl/Yn1EjySeJbW3HRuk0Rh0Y3HRrJ1DoboGYrVbWzVeBaVounICjjr8iQTT3NUkxOF" +
1148 "Ohu8HjS1iwWMuXeLsdsfIJGrCVNukM57N3S5cEeRIlFjFnmusa5BJgjIGSvRRqpI1mQq14" +
1149 "M0/ywqwWwZQ0oHhefTfPYhaO/q8lKff5OQzwIDAQAB",
1151 "CN=GTE CyberTrust Global Root",
1152 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9p" +
1153 "TAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6" +
1154 "XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQ" +
1157 "CN=GTE CyberTrust Root",
1158 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6jr11kBL65Xl0stn3JtQOQR3pNgdWct" +
1159 "W4adpU1LHWeG2q4zs9o4Q3JcevrwTcsyKx6W2+gm3rjS+9tK5wHqLWbiAxUeZWXHNSsiNQ" +
1160 "Trz7mmdAxIYRRsdDIrrqAE9scs1hnN7L+u4w0ub6W53Fmdwg+Dm/ZIwHVju93Gxe9r/h2Q" +
1163 "C=US, O=GTE Corporation, CN=GTE CyberTrust Root",
1164 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7" +
1165 "pJjTUteueLveUFMVnGsS8KDPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3" +
1166 "FQZor734sLPwKfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44Aw" +
1169 "OU=ValiCert Class 3 Policy Validation Authority",
1170 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFl" +
1171 "LWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2" +
1172 "bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPw" +
1175 "OU=ValiCert Class 1 Policy Validation Authority",
1176 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSL" +
1177 "wxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+Fiw" +
1178 "nRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQ" +
1181 "OU=ValiCert Class 2 Policy Validation Authority",
1182 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZU" +
1183 "cOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XB" +
1184 "hVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9w" +
1187 "C=hk, O=C&W HKT SecureNet CA Class A",
1188 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtBuiCqVMc2NGUUh0Y6i0jBbb9M" +
1189 "hn3qFIAv/Lo8+n39mxMeDjLihxBKZkWsZc/tCnuOo+Ctr7EX9/JCheyIqsbniqyKIYOZ5M" +
1190 "UNHwmLXvpLIbYGu/+XO0C3X5Irvp5YGgldJ2THzTp/5dlRXtB9TH3mAwAO7yLpTxhjLlWV" +
1191 "Ho34CiKgDvPIhdEeMAX1TkDEcQbLD1+DN2HDRmW9S7NGM502aUOuzNIinz9hK71CEpN6VE" +
1192 "Td+JDAQMfUF7h/MWwUMpZLTWRWerhkxljwG36mOMTnhUREcaU4aMaxgnIQvFVmYOJfbgea" +
1193 "xoAHTpmmQ8SU6e4B3IiBtQBvddCfiNixP9XQIDAQAB",
1195 "CN=IPS SERVIDORES",
1196 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyYXZhkJAk8IbPMGb" +
1197 "WOlI6H0fg3PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1gf/+rHhwLWjhOgeYlQJU" +
1198 "3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4Nu+z4cYgjui0OLzhPvYR3oydAQ" +
1201 "CN=Microsoft Root Authority",
1202 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQK9wXDmO/JOGyifl3heMOqiqY" +
1203 "0lX/j+lUyjt/6doiA+fFGim6KPYDJr0UJkee6sdslU2vLrnIYcj5+EZrPFa3piI9YdPN4P" +
1204 "AZLolsS/LWaammgmmdA6LL8MtVgmwUbnCj44liypKDmo7EmDQuOED7uabFVhrIJ8oWAtd0" +
1205 "zpmbRkO5pQHDEIJBSfqeeRKxjmPZhjFGBYBWWfHTdSh/en75QCxhvTv1VFs4mAvzrsVJRO" +
1206 "rv2nem10Tq8YzJYJKCEAV5BgaTe7SxIHPFb/W/ukZgoIptKBVlfvtjteFoF3BNr2vq6Alf" +
1207 "6wzX/WpxpyXDzKvPAIoyIwswaFybMgdxOF3wIDAQAB",
1209 "CN=Microsoft Root Certificate Authority",
1210 "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA8136gGfUWqepDCyQINA1CDx1hM" +
1211 "23B4mcidrezsNg+pFoWp6UcSkYdnzC4MgldpQOWPoENDbm36/3gLrpWAsrk+WdBeN3IpH3" +
1212 "NGQ8IpEdXuEJkLwU/vx1WBnhebcHkqOuiFkI2J8HygNY/GgpbTLX0qjLS/zhC0gyT+bruK" +
1213 "1P5FxvE5SZ25XVdduoGreUkbR3W/VIDI9qeX0UcAR9ba+Q9dpw2Ee3v5svbOcFt+ERYKx5" +
1214 "kRR8xdam5OF+1cN+5ZLSPAC1NoLeeeFt87Vu+J8zyctSfXOYNtuLoWuilZebo97CTSb/Bp" +
1215 "ZnJQbI56zk7hIzlTGZyDUITjTKeVPVtb5jMllANsClTgRNPdtbBzPkWL/vP1Nk2EJZNVf9" +
1216 "D0V8JARNntY4dBGXIpDOaER0km/VS2+whuPHNkKg0PzBwFr5o2G5MEdxlgoWsJHAQpXvEH" +
1217 "8oauMqH7HkzQM/d3EExyD8SQ8dRYik18t+iK2OLexF28RRBMkq/OyGnpoRl1vezlOI5uK3" +
1218 "/ayVwihA2+8EkN+BMznZskWlI4cGpVWJMbsGLWAOQRh9Hy61l8sR6xXVJKWU7xUUif1Lc/" +
1219 "oyW/zRMwD5WWJwBzLqLqtALXvK3SFnGzCZjxaqI6hB0bBuEZs2xN5AdJzhWGXBYB56WzjI" +
1220 "j7sEJnzUFkDltmtsqob9AL/OwTUCAwEAAQ==",
1222 "CN=NetLock Expressz (Class C) Tanusitvanykiado",
1223 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDr7LBsYYojJa9gIOPZn/yTC9tdjbChs0" +
1224 "A6gs79deB4MgOGWoaVke1T+p1A/Obo3dlbegO9XfM7DMNReZutVaDp0AMQrwq6FELZUiYR" +
1225 "IsfSIMyCpJqp/riBdp1qt9I2dT6xhgn2bm1+Trd67K5xhPYEMwglMut0rBZExuRAkx1/rQ" +
1228 "CN=NetLock Kozjegyzoi (Class A) Tanusitvanykiado",
1229 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeL" +
1230 "Vu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX" +
1231 "9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8Wg" +
1232 "D/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7tqyF" +
1233 "/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCo" +
1234 "R64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQAB",
1236 "OU=Tanusitvanykiadok, CN=NetLock Uzleti (Class B) Tanusitvanykiado",
1237 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBN" +
1238 "wcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX" +
1239 "iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvcQ7GhaQ" +
1242 "CN=Post.Trust Root CA",
1243 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1n8T5A0k2Nj76bbDsVKjTty3O+" +
1244 "L3Dl+B5gHwpuY2cNgTc6H/UgiQ8hW88jIcqNfhBhB7QaiUxz89RBXcgFHnMP5TSPWQX21t" +
1245 "JeBgu6D71sYp+E1wUBo3oA7NeCq2aPOZ1AyOXhJi/8JfWporiEequ6HZdfAsXP5twrFbMc" +
1246 "yDhxqnvpAO6BBUU1ILnEnzgAL+byemo1cwuNu40AAEA+Tl1EMG66toTWgm0pk0ueASln9L" +
1247 "u2tuIXHmCEVKHWYNN8kD4dHK3LEvcPa3gWKWG2Sn/rvhhutBn6ic2Mqg4dYv+A/hukA492" +
1248 "3RpcpMGciW3MxJHAq206iROvna7B3Nc0okPwIDAQAB",
1250 "CN=PTT Post Root CA, 0.9.2342.19200300.100.1.3=ca@ptt-post.nl",
1251 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsH7iOgHxSK1T1HHO276A4FCtma" +
1252 "KEeto6JyQ6EYE2Eg3mo5mOpMwmtQ5hxu4oq22G3y6XYfpAacmNjMQxe/pSXlZMIJ5gGl9s" +
1253 "SnjJiTyflYasd2cOpg5C6CxiSTJLBD4yQ5AOCiLKyHQOhe+DgcVb8ttshQhvTialBqt245" +
1254 "iiTl7EgODo+8zpMGzycmGuJ35T1BWUD9KPeYLZ9o+rxhPmHJh0SwBhDnlpVPKQsqMJAWX3" +
1255 "BEdsTvopK/AOBheT3ILAEd6PsDBGWUhKZs42r8fPMdGSdBQj1aq64InbEtHs1GkjuAsWST" +
1256 "POGvninF98aB13uwGqZ+Ixxv/WOmn9DBt8IwIDAQAB",
1258 "CN=Saunalahden Serveri CA, EmailAddress=gold-certs@saunalahti.fi",
1259 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5wQp3NbgUtPWTwCvHIGIvzxUcv" +
1260 "OeeWP9y2DaDHxyL8obqeIQaWd6OZ/CoCXMg4ONgxEcuP3n26mIowySIVfBquLqM35KZgO8" +
1261 "c43SHCn9x39D7Y/rV3uhQb9NczFKNyi0GFdYPGhwUJO6EB14zZPDwoLvuN8PDFjVMFdDOh" +
1262 "QlKjhZBrREzdvJXkbyS7gcQ0GB0j5Dsq4hnhtKgHymyrP0JqkuLPi39zwYD5sybxEJc8TN" +
1263 "L+jT7Ek284GN2ML/0Bpt3dgUvzLQ6cMNPgiv7dpLnWrPE4uQgmn612cjYUtb/aWAZB1696" +
1264 "XT2ncceLtR++dGgJBxcbYW+EO0Gb0Yq952ewIDAQAB",
1266 "CN=Saunalahden Serveri CA, EmailAddress=silver-certs@saunalahti.fi",
1267 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0neMvIdsNk5TqmhgRbgjd2fj7k" +
1268 "mC5mx/XpJdtRxhUteoYEsW+ut5fp1MkulXe16GMKkoPH030SHidhoZw++q2u74AZ4aOSov" +
1269 "k3UDZj9uKU2NhGOMpx8VlLQ0SbTk00GruvvEXLWecvUoyjKCY0zHRPi0HcSKCldVkK8wiV" +
1270 "QOp2gm00AHIrPOPKP7mNckPN58gkm0NIx9JNtkbmSy6f+GyKx+q1Pk0kH0EYTuR0wIHUTm" +
1271 "Vk0AfNqJQjnveAjRhea+XJ4zuTX/HM70g7XyZMUxSKm0rMXYPIwabab/Qq3z+EvOrNrFir" +
1272 "APAyPB9fPHWX8w8d9mHVoxBaJGHTnkVbOtDwIDAQAB",
1274 "C=hk, O=C&W HKT SecureNet CA Class B",
1275 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn+AlkQ8EV8LHXLFlAmYPqP3YMQ" +
1276 "5vgmz5wx6w46C9OERSx4x2EnhMfsIrjIrk+dwK4JVF3+seftJE+AMVAOzEsTx6tk22lgp3" +
1277 "vAdg7/C3N/6J/bLYB6tS/oI/vDVnM9n7LNy1WGGiDLF9lNGohGkkPZfNmwhMUImBmh/Swi" +
1278 "BvzD8OZcThSEncO/nlKjEHbqZrR6gZWq7ToXS1vMLbOT36q7DwySIJ1DxGaGwuLh/4qIwR" +
1279 "oXY1UpLXq4gh3L3pnNn4Pt4wMUwCIi9XZrtWcjk3UJmvV9D0S9Qp7alvxtOyhpGLHRBtaB" +
1280 "Zk8Q5tv15n/bKOcGXnb3K8RHWrAXb/N2RFIQIDAQAB",
1282 "C=US, O=RSA Data Security, Inc., OU=Secure Server Certification Authority",
1283 "MIGbMA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6z" +
1284 "V4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXAT" +
1285 "cXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAA" +
1288 "C=au, O=SecureNet CA Class A",
1289 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqaN8+JCzjoRM4Aq+qxIqjQw+L7" +
1290 "XdmxCIuWq3h3Ugt0vvIiMG6/BWMvfLLXDFA2+3wdDDZhMCvVVJh4fpLZ6l5XY2q+JkJViI" +
1291 "wxsbAvBdsY+fE03CUim0EDVPNoivCy2BCCRhw2iNWm0x6FQZUxf9pxP2QJmmqCnAn0J7Jy" +
1292 "nB7tvvjQNkJYGx/pUaHtoQQWIbVn8YGEiY0k1LwRhot2lna2RMbo8CvxRpe/ZEIxDpLrxe" +
1293 "Ys1bnMyjjoxRgbSiorG8qMnoKpiqu0sVoeHpkHqef+hlBegRcXpv43XeVT/L2OrIAM0llH" +
1294 "JkHu99ED5NL5F5vQLq15DBSWhuWRQl4t3dCQIDAQAB",
1296 "C=au, O=SecureNet CA Class B",
1297 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApmPZxhVadudGZcc0kfl73Va7+J" +
1298 "Y1LinKp30KHvcxUuhayNPPOQFOW/AfsbhK0rNHQ2Y/AUBOMEnhD/3rEmN4zPYWYhj1b2n9" +
1299 "fm4zdiGjwIgP6uYl/KmXzBhyxzG2C5vNwsV4YWNFrDSmJ3hoxL1SaM6ETdIkpShsgObK5s" +
1300 "/mmp5QeM7zNtKjQ1ocBq/LIO7QLMREGJBssZFkZbm3hYNLqJGZxeCc97hQ19OwT5rtY/tN" +
1301 "9NQoJDqAW3uTjMUFhK87hv6BMce2nV8a6pB7sEZesghSAFcNVVKDeJVK/WiPntlQtktT+v" +
1302 "KFApVOOPWDp5bUMT8/p8o3U9zFL20adKbMvwIDAQAB",
1304 "C=au, O=SecureNet CA Root",
1305 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApyi02Dz1v3oGkb2lQkyzfJ6IZp" +
1306 "nF2xfURVTDe8DwJFZmmL9E4HkTdmiu3Zp0z6Lpl+bBwKnD9yzVNjtzna+C2twOX1Ov625Q" +
1307 "16jwqo6rY9Kbdf5VCnzRs8BZk1Eqh2mKGe3k19eOFKu1GVizzmzgTYLTA4TBqwAYekmoFX" +
1308 "0IyQFgJ5To+wlgntE/Ts0To3j9ZfcRX/abADCMIu0oiWUb0x9he8Mjo+PGgPmD8/e63oZ4" +
1309 "X/aVw4xqSCJlhdMiefb9RBboD2EENip1xtviZRQnYtyCXJYSMw5MGNX2PJ2xzWEcsYX5A9" +
1310 "G69kzW7p990ZIh8PYKFqQ0h/dWj5O+l69SpwIDAQAB",
1312 "C=au, O=SecureNet CA SGC Root",
1313 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp1uxDYpTIbpSiDiQQmVE/Vbrc8" +
1314 "WF8wYx5Qj8jLHVescLIwq8WgkiAfinwN5XdDGLrTbMXnP39kTwMcr1LKIF8wocMHqGM+JG" +
1315 "U/Zk1kersVOUY3fEYtMvC+pfsHUCXvgrzybz3tKt62V/vC5BhPyZmumBG6ecZsf49bKEGy" +
1316 "B1ciHHhP8CRswPpmmFfVkh1Q6nXVYVT8wfQSx/Zhuv691Bo+yp5lZK/h6nxFwiny/gC3QB" +
1317 "cMhzgwoHpGie5FEOjXQxL6LG2ggQK+8lPmyGtUbnl4PAq96wrgYa58j7736tjrCaRfGb9b" +
1318 "HoMbtkAL9/kWbNqK+V6hM6Akxb68CT5EH8rQIDAQAB",
1320 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA1",
1321 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlJAMS3EpHNr2aHl6pLrn0syNr+" +
1322 "hHkJkfxirql2PoH84XV8Yas6jHfIftNTWAurpubb4X/swtG2zvigBJFuHuBl5KB12rPdFQ" +
1323 "uJFG1NTaFdiUXA7K19q/oPdJPMi7zuomgQoULZwNN0VrQcpXizjwJh8x/M80jo93wT/jq1" +
1324 "Q8J7TOMkxVE2L8/joWJc8ba6Ijt+DqAmm79yJxbXwLGZOhl5zjkWkfaOQvfRBtj2euwRCi" +
1325 "sF5jSpf35niprSa7VMnftO7FntMl3RNoU/mP6Ozl3oHWeD7uUEC0ATysFcGCOy5/8VIni3" +
1326 "Lg59v5iynDw0orM4mrXCoH/HwjHitPCCL+wQIDAQAB",
1328 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA1",
1329 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlJAMS3EpHNr2aHl6pLrn0syNr+" +
1330 "hHkJkfxirql2PoH84XV8Yas6jHfIftNTWAurpubb4X/swtG2zvigBJFuHuBl5KB12rPdFQ" +
1331 "uJFG1NTaFdiUXA7K19q/oPdJPMi7zuomgQoULZwNN0VrQcpXizjwJh8x/M80jo93wT/jq1" +
1332 "Q8J7TOMkxVE2L8/joWJc8ba6Ijt+DqAmm79yJxbXwLGZOhl5zjkWkfaOQvfRBtj2euwRCi" +
1333 "sF5jSpf35niprSa7VMnftO7FntMl3RNoU/mP6Ozl3oHWeD7uUEC0ATysFcGCOy5/8VIni3" +
1334 "Lg59v5iynDw0orM4mrXCoH/HwjHitPCCL+wQIDAQAB",
1336 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA2",
1337 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlnuSIz9g3wk8WIAI42MJl+jkC3" +
1338 "Vh1M0Oo/LjHkO6g/+6gVwvyN6Qi0wOLyn5B9aOs6Yor4Iqe8K0Zkxx9Ax0GrjbGuhoN6n5" +
1339 "oaJuHCjNbCY8jyoznp3LtHnE2WQ9lcYzqEf75QcJ3PZtuCVCTMP7Su1bLtQHqOWTECSTWG" +
1340 "59wdAez+kp19C8X0zwFRbD2MLO41sXW5SLKGsUZyQ79FLsDW58TrSZAtvJ8w+CqwH0jN4W" +
1341 "cMa8Fwdh/xFAhOosG3o6sANhB6qWjdDauYOO5J1RaXVxZIG0iFXcEIPOLaX1MJZhLjsK/I" +
1342 "dfnFyCdRMe05jR7cntchYcDAbcWSB+8F3v9wIDAQAB",
1344 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA2",
1345 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlnuSIz9g3wk8WIAI42MJl+jkC3" +
1346 "Vh1M0Oo/LjHkO6g/+6gVwvyN6Qi0wOLyn5B9aOs6Yor4Iqe8K0Zkxx9Ax0GrjbGuhoN6n5" +
1347 "oaJuHCjNbCY8jyoznp3LtHnE2WQ9lcYzqEf75QcJ3PZtuCVCTMP7Su1bLtQHqOWTECSTWG" +
1348 "59wdAez+kp19C8X0zwFRbD2MLO41sXW5SLKGsUZyQ79FLsDW58TrSZAtvJ8w+CqwH0jN4W" +
1349 "cMa8Fwdh/xFAhOosG3o6sANhB6qWjdDauYOO5J1RaXVxZIG0iFXcEIPOLaX1MJZhLjsK/I" +
1350 "dfnFyCdRMe05jR7cntchYcDAbcWSB+8F3v9wIDAQAB",
1352 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA3",
1353 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmV4egJZmI2TOnIwAPgqvCOm4BO" +
1354 "CEuG1TdU02qLXg14xOYFW2A5ebWhqn87o92ZqUMXZ0I8n37BJd2CDUHekbojd2BA8+rBZp" +
1355 "O+H/EC9WJeQzUBMJzE4Oq/Dkddtx1fxKze3bDzUFFdWwZntCeyblWeK1x8Cyx6FD/Q8vC4" +
1356 "MlJVeBu7vRNTB0kZCyj59o1dJDt7JFqSPAVtiHEtNz/stZ6q/85x9eVEUcqm2Vk2JHQkFe" +
1357 "T+s2Bw4oeFQKfMDDJBOGAwK5rHaSSlrdxdzs+LPbK7UbNud4gkyVfiBWsnUcfZfvf5Q4Ka" +
1358 "IA4tHqseM0NjFAWLiqt86BGgwXgQ3967jTvQIDAQAB",
1360 "C=hk, O=C&W HKT SecureNet CA Root",
1361 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtBiikFaM1l2/RliRJ+qddeCk66" +
1362 "JQcIdFSUmSa7c5AEt7qNpA4eYNouA3AUhNznLhXJPTw/mSDSTvSM5HKsutkjqq1pWy8hme" +
1363 "PpV8j2ACdJMWKGn+O+5deJMcejwj6WE5bMUwLR+EkgVx53TBQkfpMLGjFww2Y89Q0DKoh6" +
1364 "VAYhQROPvOL40zsIvpjnD7sJ7HXQPu9uWNcjzIvFSSz8qQ38jbrwXx61DK0QWsBbQBFZb1" +
1365 "6zihafeDQ+g8pl2lLLokFi/7DjJwphLWmTb3axuj5/zHG8jYL3XRNbPpwtaPBB3BtX4EOz" +
1366 "iJ5KMj8P3KvczrnRcGFXLt0Ob71m+z8Z0+uwIDAQAB",
1368 "C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA3",
1369 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmV4egJZmI2TOnIwAPgqvCOm4BO" +
1370 "CEuG1TdU02qLXg14xOYFW2A5ebWhqn87o92ZqUMXZ0I8n37BJd2CDUHekbojd2BA8+rBZp" +
1371 "O+H/EC9WJeQzUBMJzE4Oq/Dkddtx1fxKze3bDzUFFdWwZntCeyblWeK1x8Cyx6FD/Q8vC4" +
1372 "MlJVeBu7vRNTB0kZCyj59o1dJDt7JFqSPAVtiHEtNz/stZ6q/85x9eVEUcqm2Vk2JHQkFe" +
1373 "T+s2Bw4oeFQKfMDDJBOGAwK5rHaSSlrdxdzs+LPbK7UbNud4gkyVfiBWsnUcfZfvf5Q4Ka" +
1374 "IA4tHqseM0NjFAWLiqt86BGgwXgQ3967jTvQIDAQAB",
1376 "CN=SERVICIOS DE CERTIFICACION - A.N.C.",
1377 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsiov7CtZakOTiUYqiuXs+gX64s" +
1378 "jeQWuvA9sAWu9IN89XifvdyZIQ3ncDlRyQPse2ZyU7VZjv2Tz+JuSKO0SpdDeDCncndLip" +
1379 "ca3dlxPSyqIuuLqdyb5Z6Nly8oqFZhxHXrSHgtYP32cmpr02sfNdkFBRdjIsOy+qX2Fe41" +
1380 "TVEl3/DY0Rx4J6Nt/hTBbEdN0tau/QsfAzp/6/N2dDEi55SpSvhPsHEQhOMJN16QFUzsXe" +
1381 "FIbwrq6bciUPRHfi82yveZwuSceemHYyFpq8AN7gtCAFkRfdgBUU7jZBxCGP7tkAShnGcW" +
1382 "GlEV0AO+SndGw6Sm6D4HoxXCFl+AiHQodn5QIDAQAB",
1384 "CN=SIA Secure Client CA",
1385 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDS/LBAYGpmY1Jm5mkJcY2BmB4dHfPgSQ" +
1386 "3IK2/Qd1FFxZ1uo1xw3hV4Fh5f4MJi9H0yQ3cI19/S9X83glLGfpOd8U1naMIvwiWIHXHm" +
1387 "2ArQeORRQjlVBvOAYv6WpW3FRsdB5QASm2bB4o2VPtXHDFj3yGCknHhxlYzeegm/HNX8ow" +
1390 "C=IT, O=SIA S.p.A., L=Milano, CN=SIA Secure Server CA",
1391 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA28ELzCfTEiIuuWQWdKxZJ+IqkA" +
1392 "CSntWYXCtRbhsTb1RvShCihethC+ztnH7Of2WTbsxsQZzILarGs5v7THCcEXXzcom6iQCt" +
1393 "xy5J53PagLIs/vKXmfQCGzQvOaqL5u8F/Ln1ulR/ob+OHkg2Mwl0Yac9x5skx8OJzcpOKD" +
1394 "EjBhxiFY7fTxtrLUri9LDczvOQ/XmBE8E+Lma8+SJNCy9iM42oK+rpb3OnN5QEL+leTQ3p" +
1395 "7XwyP3lK5jp2KSBQ84+CRHJsMDRIWKpdGz8B6yHs6n6oK4Rd9sExlU8pe7U1t/60BlewFN" +
1396 "fyVVmMupu5MT/lqqrvJXCVkjZB8VWfwQhEnQIDAQAB",
1398 "OU=Public CA Services",
1399 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwOeC2xUTrnnCtF+SjyO8uvfG0Q" +
1400 "Cv1lRp8V2mYvhh0Zzeyjss6VwWJzTmuNHKdO8leGRt/hzoiXMxU2dnhsStamjnClZEgzpY" +
1401 "R4l3Gtpv8vkHQMk9Ae9q0dlrhJ7FaytOtyz4pGpXq2gxuhlmuuwbV/vOStZLeMPBgT1Llj" +
1402 "CZqcMt4uQSJgqkYxIc1HfIgdSnVUMt/ARWndwLrrdsCtozkIgFyX5UgujSMtDXAUkqNZB5" +
1403 "OXPWi7xhzYdtUBUFTKnoSkcxiwXM5flC1xJg+Do/o6k2GqWGNiymBIMJ9lLFsH0fiEGQmM" +
1404 "VlaJYQshPJFkm9Kr6wSKfC/S1eVtA3TVhR+wIDAQAB",
1406 "OU=TC TrustCenter Class 1 CA",
1407 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwKeu0drOu17ZbtF7nveOxnEkEV1uhq9" +
1408 "l/Exv9umGr2Odx3y0AlF1RSH0j73VihJA8Ch9ZEXQvjoCl/TACPSlSzXIaSSGcvMtSjkih" +
1409 "Y5bIEIUwaVd0RcBahsbVPeBoV30xaiSNRZc+MX5oZjJuJG3sMjbJQcrwMUTIo2HKG6A2Hw" +
1412 "OU=TC TrustCenter Class 2 CA",
1413 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaOOjtMgApcYMBDb+MAdzaxq05pKmKL9" +
1414 "WLXGhfUMZi9Wa9ypEi7KodUdc9s1Gyg05dy0mw8ExV5Wstx4ULMBySToLUygLt92++3ODj" +
1415 "FLgFU/Ka9FaLWp6Fk9G0glauTbuoS1cWvP74WJ74KY2we814yU+si2cM8Zz7/FebV1xPDQ" +
1418 "OU=TC TrustCenter Class 3 CA",
1419 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2tME1BS4NjeygQGocDiemUJJrUBsH3i" +
1420 "7ndszg2vyEqF6MY2orTdlOAnYRwQvyjXnKALbxsA7X+6QXPa+raXqWJ7+vM6GaKlmqxLU3" +
1421 "CPISpTG2Q/UylnEoKKuNKIbfu+7jDH0w1sNSq49dJ5xrwKPnBWtXSUSzbupkz9KOelB3dw" +
1424 "OU=TC TrustCenter Class 4 CA",
1425 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/L2PWNnuyDdNV9WRs5iVdxrTIFLolOI" +
1426 "PrVmKlVallo/QjmcJLudDNVGemo6CjqTMrduS9rXey7VwSdMPFtg9SmnKTQ5BiZhUPRaXd" +
1427 "4N24b0BuV8F5cqNgqrp2HRKJU1r8Ar7hCRPFSi/cPYsZrdeLJEX7TPTNXDUdKUxR8/JsVQ" +
1430 "CN=Thawte Premium Server CA",
1431 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSNjZqi9fCW57agUFijzjuSQRV1tDvHB" +
1432 "uVFkfvGEg1OlL0K2oGjzsv6lbjr4aNnhf3nrRldQJN78sJoiFR2JvQZ9C6DZIGFHPUk8uX" +
1433 "KgCcXE4MvPoVUvzyRG7aEUpuCJ8vLeP5qjqGc7ZGU1jIiQW9gxG4cz+qB430Qk3nQJ0cNw" +
1436 "C=hk, O=C&W HKT SecureNet CA SGC Root",
1437 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqFNPj0Pdr+zBtA0bX7cIoprIQu" +
1438 "Nt1yUa3+DKvC8iJPlpIr0arVHncfe1dtTzPsg+EdBNe5keGLeezT5hG0URS1sm3Ck8AE0R" +
1439 "2h2Pnh903hVAvDDJD9/4LXzYjZ2g4J+wzydgzzgRCO82L3xONh0mAqf01FBDgUnr3beWFD" +
1440 "BjMtEDzSG8N5EePmWuFoL2FWBLUTuW5RnowvemBYE6qH8YWD53w1kAg/T1eUlgpy4DPgH9" +
1441 "heLfoZqJ2fhkCiuEzUPNJTUAXjBmdKHHCHWsSSeC17CVNW4dmYDrkqAtWtY4u7VHJ6sazL" +
1442 "9TU8FGsm/o101XEd2wNUgfqybqVg24CjC22wIDAQAB",
1444 "CN=Thawte Server CA",
1445 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTpFBuyP9Wa+bPXbbqDGh1R6KqwtqEJf" +
1446 "yo9EdR2oW1IHSUhh4PdcnpCGH1Bm0wbhUZAulSwGLbTZme4moMRDjN/r7jZAlwxf6xaym2" +
1447 "L0nIO9QnBCUQly/nkG3AKEKZ10xD3sP1IW1Un13DWOHA5NlbsLjctHvfNjrCtWYiEtaHDQ" +
1450 "CN=UTN - DATACorp SGC",
1451 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLi" +
1452 "t6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZD0/W" +
1453 "w5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK4ESGoE1O1k" +
1454 "duSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykqlXvY8qdOD1R8oQ2A" +
1455 "swkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv33i+Ybqypa4ETLyorG" +
1456 "kVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB",
1458 "CN=UTN-USERFirst-Hardware",
1459 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsffDOD+0qH/POYJRZ9Btn9L/WP" +
1460 "PnnyvsDYlUmbk4mRb34CF5SMK7YXQSlh08anLVPBBnOjntKxPNZuuVCTOkbJex6MbswXV5" +
1461 "nEZejavQav25KlUXEFSzGfCa9vGxXbanbfvgcRdrooj7AN/+GjF3DJoBerEy4ysBBzhuw6" +
1462 "VeI7xFm3tQwckwj9vlK3rTW/szQB6g1ZgXvIuHw4nTXaCOsqqq9o5piAbF+okh8widaS4J" +
1463 "M5spDUYPjMxJNLBpUb35Bs1orWZMvD6sYb0KiA7I3z3ufARMnQpea5HW7sftKI2rTYeJc9" +
1464 "BupNAeFosU4XZEA39jrOTNSZzFkvSrMqFIWwIDAQAB",
1466 "CN=UTN-USERFirst-Network Applications",
1467 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/uRoeQ2VYWsBjRboJpYsvi1Dw" +
1468 "V3g64ysXaSaOwjSsl2P+Octjd5A7mraY0HJbYZZ+SwGxhzYUrofs3TL2TjpnwM+heAow1H" +
1469 "iU9RcS/u/D/5uBaAh4mTJSCaQ4JpJHYoWTWhHcB/gwZkFiAs00mkhbTAYX9RCPhoFZGAy6" +
1470 "XV7js69IQEXmBZp4w0cu64eMXROxJKb35lJ7mkVcW5b0OkxR0smcBSpHhMFbNAmAhrQ8YB" +
1471 "sHp79WscIj/L7/+o0DpLdhWe0tHGLuPbVxsyorhv6IamP3Cr5XCSq0QeQFD7nKNi5GxuoM" +
1472 "je4oBC+ukv6M4yBI98jbccozU8Fd2ew66XpQIDAQAB",
1474 "CN=VeriSign Class 3 Public Primary Certification Authority - G3",
1475 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy7qcUvx4Hxoebxs3c734yWuUEj" +
1476 "BP8DZH9dCRCvUXyKVhwRZATfuKYZDldiDBEQZ9qyxupvURQY76La0qYVmkZyZM0Oi8Ultw" +
1477 "IARY0XrJpGm8gxdkrQWLvNBYzo2M9evwQkkLnZcnZzJu4a6TFRxwvCBNLxjekojobIVXER" +
1478 "rpfuMmEVSiRZZVg8owiejc2KPtKoA/f3llVz4VIGYIL5WTv6pHL6hGl/AS4v7CCitR5nbm" +
1479 "t0a34g2mzKjDTFlVieboU1wc6p3wYhYLp8lfDPDewnbOr/dq8vpBpqIzFMnlemPTnmI31Y" +
1480 "Vlng7mUyR0G14dElNbxyzng0k7Fa6KaLlXlwIDAQAB",
1482 "CN=VeriSign Class 4 Public Primary Certification Authority - G3",
1483 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArculEWnGWavxj7UZD1bOzLUfIO" +
1484 "SeJiVL4HNliVne0IPk9Q+1u63xfOgh/OToDO58RSIZdpK0E7cgWwn6Ya6o8qWNhcIq1t5m" +
1485 "NtKbAvSokmB8nGm0jyQe0IZS9jKcQVgeIr3NRWKVCG7QZt1ToszwENxUc4sEoUYzM1wXQL" +
1486 "meTdPzvlWD6LGJjlp8mpYikDuIJfLSU4gCDAt48uY3F0swRgfkgG2m2JYu6Cz4EbM4DWam" +
1487 "m+rJI1vbjuLzE44aWS2qAvDspIdm3ME/9di59OyCxtI9lR3lwE+EydmjRCgGatdFrPBrau" +
1488 "9OX/gRgh44YzRmUNQ+k3P6MMNmrf+TLZfvAwIDAQAB",
1490 "OU=VeriSign Trust Network",
1491 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRN" +
1492 "zjMHPVKmIquNDMHO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDH" +
1493 "qGKB3FtKqsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHw" +
1496 "OU=VeriSign Trust Network",
1497 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRN" +
1498 "zjMHPVKmIquNDMHO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDH" +
1499 "qGKB3FtKqsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHw" +
1502 "OU=VeriSign Trust Network",
1503 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm" +
1504 "1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71" +
1505 "lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZw" +
1508 "OU=VeriSign Trust Network",
1509 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm" +
1510 "1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71" +
1511 "lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZw" +
1515 public static boolean alwaysFalse = false;
1517 private static volatile boolean initializationFinished = false;
1518 static class EntropySpinner extends Thread {
1519 boolean stop = false;
1521 EntropySpinner() { start(); }
1525 // without this line, GCJ will over-optimize this loop into an infinite loop. Argh.
1526 if (alwaysFalse) stop = true;
1533 EntropySpinner[] spinners = new EntropySpinner[10];
1534 for(int i=0; i<spinners.length; i++) spinners[i] = new EntropySpinner();
1536 for(int i=0; i<pad1.length; i++) pad1[i] = (byte)0x36;
1537 for(int i=0; i<pad2.length; i++) pad2[i] = (byte)0x5C;
1538 for(int i=0; i<pad1_sha.length; i++) pad1_sha[i] = (byte)0x36;
1539 for(int i=0; i<pad2_sha.length; i++) pad2_sha[i] = (byte)0x5C;
1542 if (Log.on) Log.info(SSL.class, "reading in trusted root public keys...");
1543 trusted_CA_public_keys = new SubjectPublicKeyInfo[base64_encoded_trusted_CA_public_keys.length / 2];
1544 trusted_CA_public_key_identifiers = new String[base64_encoded_trusted_CA_public_keys.length / 2];
1545 for(int i=0; i<base64_encoded_trusted_CA_public_keys.length; i+=2) {
1546 trusted_CA_public_key_identifiers[i/2] = base64_encoded_trusted_CA_public_keys[i];
1547 byte[] b = Base64.decode(base64_encoded_trusted_CA_public_keys[i+1]);
1548 DERInputStream dIn = new DERInputStream(new ByteArrayInputStream(b));
1549 trusted_CA_public_keys[i/2] = new SubjectPublicKeyInfo((DERSequence)dIn.readObject());
1552 } catch (Exception e) {
1553 if (Log.on) Log.info(SSL.class, e);
1556 if (Log.on) Log.info(SSL.class, "generating entropy...");
1557 randpool = new byte[10];
1558 try { Thread.sleep(100); } catch (Exception e) { }
1559 for(int i=0; i<spinners.length; i++) {
1560 spinners[i].stop = true;
1561 randpool[i] = spinners[i].counter;
1564 MD5Digest md5 = new MD5Digest();
1565 md5.update(randpool, 0, randpool.length);
1566 intToBytes(System.currentTimeMillis(), randpool, 0, 4); md5.update(randpool, 0, 4);
1567 intToBytes(Runtime.getRuntime().freeMemory(), randpool, 0, 4); md5.update(randpool, 0, 4);
1568 intToBytes(Runtime.getRuntime().totalMemory(), randpool, 0, 4); md5.update(randpool, 0, 4);
1569 intToBytes(System.identityHashCode(SSL.class), randpool, 0, 4); md5.update(randpool, 0, 4);
1570 Properties p = System.getProperties();
1571 for(Enumeration e = p.propertyNames(); e.hasMoreElements();) {
1572 String s = (String)e.nextElement();
1573 byte[] b = s.getBytes();
1574 md5.update(b, 0, b.length);
1575 b = p.getProperty(s).getBytes();
1576 md5.update(b, 0, b.length);
1578 randpool = new byte[md5.getDigestSize()];
1579 md5.doFinal(randpool, 0);
1581 if (Log.on) Log.info(SSL.class, "SSL is initialized.");
1582 initializationFinished = true;
1583 SSL.class.notifyAll();
1588 * A PKCS1 encoder which uses SSL's built-in PRNG instead of java.security.SecureRandom.
1589 * This code was derived from BouncyCastle's org.bouncycastle.crypto.encoding.PKCS1Encoding.
1592 private static class PKCS1 implements AsymmetricBlockCipher {
1593 private static int HEADER_LENGTH = 10;
1594 private AsymmetricBlockCipher engine;
1595 private boolean forEncryption;
1596 private boolean forPrivateKey;
1598 public PKCS1(AsymmetricBlockCipher cipher) { this.engine = cipher; }
1599 public AsymmetricBlockCipher getUnderlyingCipher() { return engine; }
1601 public void init(boolean forEncryption, CipherParameters param) {
1602 engine.init(forEncryption, (AsymmetricKeyParameter)param);
1603 this.forPrivateKey = ((AsymmetricKeyParameter)param).isPrivate();
1604 this.forEncryption = forEncryption;
1607 public int getInputBlockSize() { return engine.getInputBlockSize() - (forEncryption ? HEADER_LENGTH : 0); }
1608 public int getOutputBlockSize() { return engine.getOutputBlockSize() - (forEncryption ? 0 : HEADER_LENGTH); }
1610 public byte[] processBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1611 return forEncryption ? encodeBlock(in, inOff, inLen) : decodeBlock(in, inOff, inLen);
1614 private byte[] encodeBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1615 byte[] block = new byte[engine.getInputBlockSize()];
1616 if (forPrivateKey) {
1617 block[0] = 0x01; // type code 1
1618 for (int i = 1; i != block.length - inLen - 1; i++)
1619 block[i] = (byte)0xFF;
1621 getRandomBytes(block, 0, block.length);
1622 block[0] = 0x02; // type code 2
1624 // a zero byte marks the end of the padding, so all
1625 // the pad bytes must be non-zero.
1626 for (int i = 1; i != block.length - inLen - 1; i++)
1627 while (block[i] == 0)
1628 getRandomBytes(block, i, 1);
1631 block[block.length - inLen - 1] = 0x00; // mark the end of the padding
1632 System.arraycopy(in, inOff, block, block.length - inLen, inLen);
1633 return engine.processBlock(block, 0, block.length);
1636 private byte[] decodeBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
1637 byte[] block = engine.processBlock(in, inOff, inLen);
1638 if (block.length < getOutputBlockSize())
1639 throw new InvalidCipherTextException("block truncated");
1640 if (block[0] != 1 && block[0] != 2)
1641 throw new InvalidCipherTextException("unknown block type");
1643 // find and extract the message block.
1645 for (start = 1; start != block.length; start++)
1646 if (block[start] == 0)
1648 start++; // data should start at the next byte
1650 if (start >= block.length || start < HEADER_LENGTH)
1651 throw new InvalidCipherTextException("no data in block");
1653 byte[] result = new byte[block.length - start];
1654 System.arraycopy(block, start, result, 0, result.length);