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