Bug 1069559 - Implement dynamic pinning backend Part 3/3 idl tests. r=keeler a=lmandel
authorCamilo Viecco <cviecco@mozilla.com>
Fri, 12 Sep 2014 14:59:37 -0700
changeset 224936 6f26d4fce19caa0033dee5ca29b627a906882350
parent 224935 e3b3c8386ae779dcf606578bfa2899a5a9d77f7f
child 224937 b8aa98daf4a7ec59277b4d521be976b588c2927c
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskeeler, lmandel
bugs1069559
milestone34.0a2
Bug 1069559 - Implement dynamic pinning backend Part 3/3 idl tests. r=keeler a=lmandel
security/manager/ssl/tests/unit/test_pinning_dynamic.js
security/manager/ssl/tests/unit/test_pinning_dynamic/badca.der
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-a.pinning2.example.com-badca.der
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-a.pinning2.example.com-pinningroot.der
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-b.pinning2.example.com-badca.der
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-b.pinning2.example.com-pinningroot.der
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-www.example.com-alt-a.pinning2.example-badca.der
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-www.example.com-alt-a.pinning2.example-pinningroot.der
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.a.pinning2.example.com-badca.der
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.a.pinning2.example.com-pinningroot.der
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.b.pinning2.example.com-badca.der
security/manager/ssl/tests/unit/test_pinning_dynamic/cn-x.b.pinning2.example.com-pinningroot.der
security/manager/ssl/tests/unit/test_pinning_dynamic/generate.py
security/manager/ssl/tests/unit/test_pinning_dynamic/pinning_root_generate.py
security/manager/ssl/tests/unit/test_pinning_dynamic/pinningroot.der
security/manager/ssl/tests/unit/test_pinning_dynamic/pinningroot.key
security/manager/ssl/tests/unit/test_sss_savestate.js
security/manager/ssl/tests/unit/xpcshell.ini
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic.js
@@ -0,0 +1,204 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// The purpose of this test is to create a site security service state file
+// and see that the site security service reads it properly.
+
+function writeLine(aLine, aOutputStream) {
+  aOutputStream.write(aLine, aLine.length);
+}
+
+let gSSService = null;
+
+let profileDir = do_get_profile();
+let certdb;
+
+function certFromFile(filename) {
+  let der = readFile(do_get_file("test_pinning_dynamic/" + filename, false));
+  return certdb.constructX509(der, der.length);
+}
+
+function loadCert(cert_name, trust_string) {
+  let cert_filename = cert_name + ".der";
+  addCertFromFile(certdb, "test_pinning_dynamic/" + cert_filename, trust_string);
+  return certFromFile(cert_filename);
+}
+
+function checkOK(cert) {
+  return checkCertErrorGeneric(certdb, cert, 0, certificateUsageSSLServer);
+}
+
+function checkFail(cert) {
+  return checkCertErrorGeneric(certdb, cert, MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE,
+                               certificateUsageSSLServer);
+}
+
+const NON_ISSUED_KEY_HASH = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+const PINNING_ROOT_KEY_HASH ="kXoHD1ZGyMuowchJwy+xgHlzh0kJFoI9KX0o0IrzTps=";
+
+function run_test() {
+  Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
+
+  let stateFile = profileDir.clone();
+  stateFile.append(SSS_STATE_FILE_NAME);
+  // Assuming we're working with a clean slate, the file shouldn't exist
+  // until we create it.
+  do_check_false(stateFile.exists());
+  let outputStream = FileUtils.openFileOutputStream(stateFile);
+  let now = (new Date()).getTime();
+  writeLine("a.pinning2.example.com:HPKP\t0\t0\t" + (now + 100000) + ",1,0,kXoHD1ZGyMuowchJwy+xgHlzh0kJFoI9KX0o0IrzTps=\n", outputStream);
+  writeLine("b.pinning2.example.com:HPKP\t0\t0\t" + (now + 100000) + ",1,1,kXoHD1ZGyMuowchJwy+xgHlzh0kJFoI9KX0o0IrzTps=\n", outputStream);
+
+  outputStream.close();
+  Services.obs.addObserver(checkStateRead, "data-storage-ready", false);
+  do_test_pending();
+  gSSService = Cc["@mozilla.org/ssservice;1"]
+                 .getService(Ci.nsISiteSecurityService);
+  do_check_true(gSSService != null);
+}
+
+function checkStateRead(aSubject, aTopic, aData) {
+  do_check_eq(aData, SSS_STATE_FILE_NAME);
+  do_check_neq(gSSService, null);
+
+  // Initializing the certificate DB will cause NSS-initialization, which in
+  // turn initializes the site security service. Since we're in part testing
+  // that the site security service correctly reads its state file, we have to
+  // make sure it doesn't start up before we've populated the file
+  certdb = Cc["@mozilla.org/security/x509certdb;1"]
+             .getService(Ci.nsIX509CertDB);
+
+  loadCert("pinningroot", "CTu,CTu,CTu");
+  loadCert("badca", "CTu,CTu,CTu");
+
+  // the written entry is for a.pinning2.example.com without subdomains
+  // and b.pinning2.example.com with subdomains
+  checkFail(certFromFile('cn-a.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-a.pinning2.example.com-pinningroot.der'));
+  checkOK(certFromFile('cn-x.a.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-x.a.pinning2.example.com-pinningroot.der'));
+  checkFail(certFromFile('cn-www.example.com-alt-a.pinning2.example-badca.der'));
+  checkOK(certFromFile('cn-www.example.com-alt-a.pinning2.example-pinningroot.der'));
+
+  checkFail(certFromFile('cn-b.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-b.pinning2.example.com-pinningroot.der'));
+  checkFail(certFromFile('cn-x.b.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-x.b.pinning2.example.com-pinningroot.der'));
+
+  do_check_true(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                        "a.pinning2.example.com", 0));
+  do_check_false(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                         "x.a.pinning2.example.com", 0));
+  do_check_true(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                        "b.pinning2.example.com", 0));
+  do_check_true(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                        "x.b.pinning2.example.com", 0));
+
+
+  // add withSubdomains to a.pinning2.example.com
+  gSSService.setKeyPins("a.pinning2.example.com", true, 1000, 2,
+                        [NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH]);
+  checkFail(certFromFile('cn-a.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-a.pinning2.example.com-pinningroot.der'));
+  checkFail(certFromFile('cn-x.a.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-x.a.pinning2.example.com-pinningroot.der'));
+  checkFail(certFromFile('cn-www.example.com-alt-a.pinning2.example-badca.der'));
+  checkOK(certFromFile('cn-www.example.com-alt-a.pinning2.example-pinningroot.der'));
+  checkFail(certFromFile('cn-b.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-b.pinning2.example.com-pinningroot.der'));
+  checkFail(certFromFile('cn-x.b.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-x.b.pinning2.example.com-pinningroot.der'));
+
+  do_check_true(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                        "a.pinning2.example.com", 0));
+  do_check_true(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                        "x.a.pinning2.example.com", 0));
+
+  // Now setpins without subdomains
+  gSSService.setKeyPins("a.pinning2.example.com", false, 1000, 2,
+                        [NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH]);
+  checkFail(certFromFile('cn-a.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-a.pinning2.example.com-pinningroot.der'));
+  checkOK(certFromFile('cn-x.a.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-x.a.pinning2.example.com-pinningroot.der'));
+  checkFail(certFromFile('cn-www.example.com-alt-a.pinning2.example-badca.der'));
+  checkOK(certFromFile('cn-www.example.com-alt-a.pinning2.example-pinningroot.der'));
+
+  checkFail(certFromFile('cn-b.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-b.pinning2.example.com-pinningroot.der'));
+  checkFail(certFromFile('cn-x.b.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-x.b.pinning2.example.com-pinningroot.der'));
+
+  do_check_true(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                        "a.pinning2.example.com", 0));
+  do_check_false(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                         "x.a.pinning2.example.com", 0));
+  do_check_true(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                        "b.pinning2.example.com", 0));
+  do_check_true(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                        "x.b.pinning2.example.com", 0));
+
+  // failure to insert new pin entry leaves previous pin behavior
+  try {
+    gSSService.setKeyPins("a.pinning2.example.com", true, 1000, 1,
+                          ["not a hash"]);
+    do_check_true(false); // this shouldn't run
+  } catch(e) {
+  }
+  checkFail(certFromFile('cn-a.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-a.pinning2.example.com-pinningroot.der'));
+  checkOK(certFromFile('cn-x.a.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-x.a.pinning2.example.com-pinningroot.der'));
+  checkFail(certFromFile('cn-www.example.com-alt-a.pinning2.example-badca.der'));
+  checkOK(certFromFile('cn-www.example.com-alt-a.pinning2.example-pinningroot.der'));
+
+  checkFail(certFromFile('cn-b.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-b.pinning2.example.com-pinningroot.der'));
+  checkFail(certFromFile('cn-x.b.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-x.b.pinning2.example.com-pinningroot.der'));
+
+  do_check_true(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                        "a.pinning2.example.com", 0));
+  do_check_false(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                         "x.a.pinning2.example.com", 0));
+  do_check_true(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                        "b.pinning2.example.com", 0));
+  do_check_true(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                        "x.b.pinning2.example.com", 0));
+
+  // Incorrect size results in failure
+  try {
+    gSSService.setKeyPins("a.pinning2.example.com", true, 1000, 2,
+                          ["not a hash"]);
+    do_check_true(false); // this shouldn't run
+  } catch(e) {
+  }
+
+  // Ensure built-in pins work as expected
+  do_check_false(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                         "nonexistent.example.com", 0));
+  do_check_true(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+                                        "include-subdomains.pinning.example.com", 0));
+
+  gSSService.setKeyPins("a.pinning2.example.com", false, 0, 1,
+                        [NON_ISSUED_KEY_HASH]);
+
+  do_timeout(1250, checkExpiredState);
+}
+
+function checkExpiredState() {
+  checkOK(certFromFile('cn-a.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-a.pinning2.example.com-pinningroot.der'));
+  checkOK(certFromFile('cn-x.a.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-x.a.pinning2.example.com-pinningroot.der'));
+  checkOK(certFromFile('cn-www.example.com-alt-a.pinning2.example-badca.der'));
+  checkOK(certFromFile('cn-www.example.com-alt-a.pinning2.example-pinningroot.der'));
+
+  checkFail(certFromFile('cn-b.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-b.pinning2.example.com-pinningroot.der'));
+  checkFail(certFromFile('cn-x.b.pinning2.example.com-badca.der'));
+  checkOK(certFromFile('cn-x.b.pinning2.example.com-pinningroot.der'));
+
+  do_test_finished();
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..53dc999cc6495b18a7543db721b23c731e37aa30
GIT binary patch
literal 734
zc$_n6V!CC}#CT`{GZP~d6C<MmFB_*;n@8JsUPeZ4Rt5tBLp}o@Hs(+kW**k0#FXSj
z137VCLlXl_Lo*{oBO_C@C~;mR5Z4&W#iFB$Q3=^tMpg#qCPsb+pg0#(6C)$T_0~Fe
zjb*azf<9W-Z?fBii%fc-Z4;dS<&xz5U#BtztkRcTTdh6dTkf_bZ|=nz=ep%qv`qUF
zo{&D(@iE_P$FMsm`%<;51K;xO6JJ05OOo2LkAe|Oi3Ys&+Do}ETz=@lwqVgxy$~*k
zH#6iOG%3AQPitFqrhm2lQkh2Xx%d62d@YO9+FX6_!S%)69dDPZPV_81xVPVE#lszM
zJeYC>f2g1EIMr`$Eh_qb;<E`hn+%&5i0_y(-T9=D;l*Pa%;v`V%;xo9vW_0_Jrl7b
z%CVtgq4}-p$5?EVIvvWE>7VdsJov9Q_RJmCp0;!M_SZeyHa(~5(8Leie5V~Ibeq-t
zzV|o#n#{z^$iTSR-oVy?9~f@3!i<dnSy&C2fs_F^NPwS(1sFSQ2C^UyABz}^h*rTJ
zK8G@;1tLNxd{(Wx^6P+pLOoi{F@r+3Ig-`(+id1PIh;Z2uTQ*CnEvdv`oDhPS!Js_
z?yNmGU20bUjbhuER<>IXCaiy4`D^8e&LcsRC$<P}$nM*;PtI<NP_pcYKayX!&nWEl
zKDa}<@wI@FlUn!g_}L3`-rRAK<JclulPt<);;G!$?`{9d|Dh81ldhoo_E8qc6uhU}
zEZL(~Slrnl)7Kbrrja>X;+7j@%gVAT{LPwDmYe&}Uv5d<6}0a~f}yKijlT2Uh_+4V
z#94UUe`PdTbg*PP+3U(?7rss^emCn@MU;KU&r-KbMnXw$muIv*ZFfDyt*XGjPSxwZ
kThZ(Zkqdhd@Uxh0Pnxfs`{b=X$HMrln!KSagHG)Q0P7(jCIA2c
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..780e7ae54d7bab6f1d1926a6020248f59d58942b
GIT binary patch
literal 734
zc$_n6V!CC}#CT`{GZP~d6C;-aFB_*;n@8JsUPeZ4Rt5tBLp}o@Hs(+kW**k0#FXSj
z137VCLlXl_Lo*{oBO_C@C~;mR5Z4&WHBdB^H;{$s5KGi6$jr;j%u6@YORY%EEyzjL
zOU};)+NXqU4<joBa}y&!15licsfm%1;Y+;UD}f!%fqUl&%<)ZhESHandfgM9XYo^K
z(fp&;4>pC}etP@g_G5}W@BE)Gxh>8)fGx*YHux~->u<kK+<UW{|E=hMzLaw|-(K#M
z{Kc|qRq(V00*-U`Z?IXUr~WzAV<o%V4wsn5-4gn*4wv7XGo5E*;i?s!Rd=^a{r|G6
zw)RJL-KiM`F2_FKUR&JsX!a6;-RY|D8cW>MUmY{xobhS-SFXxEb9JV*R&2d;T=&&<
z-^R+BJh5}%KJ&=Zc~JdBRxhD#!-TiZ39WyECpf%ifB1RFkG-d@3f!#CDmS0smgthq
zwPSzDouAfD=S`P8{@&4T_UOh3nV<IjM)GO-C*Gd_{$a+RN+xDT2FAsD208|uz<`t$
zW??d5Fpvi^m02VV#2Q4j3hwYZlqoF`5jx?sYSoor2lNx_(PEAn6p(sstV;3cOF#S7
z|Eu1?c3}7Y>2Fm;L!Y;QxX<MCOV)R5V%hZN8+Js79}P~}Vdu4jNq(=fRTodYB=0%F
z@4esSO;;SdsKmSG^6t|DQ$>Bw>b0DU;$+gEF?Axpz{9RN6R$)r{<3%Kw>OUJVNXiF
zTrfyVJo&hFXT_SRhIg;H<){Bz9O4kOr1ggMDT_%FF0SAF9>v}4)x4Z|{QkBj{Eiu~
zeYaj&tINS!X<Zxg$WplXwY<@l+Xj3yjie;anr3j#{U`W*+xD}YV<wwTZmklZDr_^k
zNc_!R>4rW3!~S<HWr=1x#v{Nm=iDNx8Bh1BoN_mCo3#4qZ{~FyJZFENcj4MIU)Fuk
Fy8(CvIJ^J=
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..09603960bb505c29ff6d1bd717e048a32cd75d12
GIT binary patch
literal 890
zc$_n6VlFdiVv1Y9%*4pV#K>j9%f_kI=F#?@mywa1mBFBKwIR0wCmVAp3!5-gXfTY!
z!NcV2XeeeN0^+dq@cQPL=9MI7<|%|_rj{Ej87P3nxp*Xf^Q$s*auOAE6#_Ez@-p+%
z6-rWzOB8^5Weuc3YPfksf>V=Ai!w_p6<qVuGxJhYi-5`uO$>}c(#$;C5dqG@8L2rr
za1%m+CV*%Spp`|X#U<tWMI{-Pnm|Jh<ivS_IxP*&j0}y8OwFUjd5u6^V<^`^(NNw%
z7GkbgqFw>SKqI}>ip1Q4oK(H!{9J=3MkVAhU}R-rZerwT0E%-lH8C<W9RB{-R^y>b
z$yS!~gb5#K7{tX+vpdw`>5<s6XFun9+Y0-)(QCZrcRrqYyZGUx`G3uh&nr1P)m`{!
zLf)$`bF*mGeJeYbviC>-O*h;hkzt;5E<<2v<}Kgu*qhU4>pyK&TPV5h>qDJ3mQ@X3
zd0#CssuDJrSNQ*7WlpZpz8kX>xDpTl-1bgjUzfzZMK`q{c7}P$_5?GEM!obtCcn`;
zNH~1U(b=~OxtcXuAI1yX&3dALrtFN^t;azhU3c!gztTffu5jhM{ZD^3G5!+&bLA7y
z2?m+2yPcCB-6+?%w&i7W`P5gFSMK(of6(yMsTG|IKk(-G?tGf#cjG}rY(doFdqoeu
z!}Zgdm>C%u7wZ}5fD?kOFbk6bgMmDVsmvl_Al4xA;XPw?#a_m}eU6;5Haen)E57C|
zMN3u8pn%lSW|yjR7XG;JkY3t!hTz?HO4oxDrktI~!n4Tp?U$cIPTSP9T7wqtK2vnN
za?4dlhc4;;aldBO#E3hb?a_G8by&{)M&pq;kwy#eI4<B>B($eUo+X8a#Wp(m(Sp@!
zi@r)$-u};hM54x5ppj8msYcrQ?oY-RhPjXS?n(%(DiVtRe}BH(cB3y^g^nh>V-nWO
z$Z1_#oOhA8@%0@3p9|X7*Cj2Ns$Be4nya^=acOF%QYfSEiRE6${8Q9?Ho4r|cJ$Sy
zTJxNHmGYbd&T}sAs(#&25IimD)aplF3RND8`<6IHG6dI8OO0E&&BaaXyWGKw8wc!U
T<l+;3BgEfr6m#yodHy*7m|#@B
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..782b3cedabb9df0d22bf9bbecbf52fcf54aa7373
GIT binary patch
literal 734
zc$_n6V!CC}#CT`{GZP~d6C<wyFB_*;n@8JsUPeZ4Rt5tBLp}o@Hs(+kW**k0#FXSj
z137VCLlXl_Lo*{oBO_DuC~;mR5Z4&WHBdB^H;{$s5KGc4$jr;j%u6@YORY%EEyzjL
zOU};)+NXqU4<joBa}y&!15licsfm%1;moat)4CMW116N5+B50djhd_4J0FyG>B$QI
z|0gi-=tcIWZ+@NrHSK>y{m0;>r9l^_wA6NfXrCKAbLz4u=6^3PtN*~M(Vy~{FJNNU
z&M!O<Cf8fDO%pSzDdJ!3H+7<B>4CX2=HED3zQ4VncI4Nw#zS9kMIM|HxbQWPDZ`v7
zZ<F5Rt|IBu+ckQ>Tiu!2RDD{rcEcK%g#L_>a|e=~vtCa8RVy3D#x8nH<6n%WipkO=
z4C(^+moz?K<*Wbv$lK8S0T)YH%Hrj_on{#9{-2*T@8*O1h5p5YpVK2E0>kGpTQ>ez
z%$$~2wj@hvx=lT2iYsG`_DtoOb8Y^suZdt^R%H0MKd+mKnUR5Uv7UjB0VgmZWrbOo
z3>XaLK}=;92?MbP5v_tdd=6zw3q*uY_^euW<<|lIgnG1?V+IFg!MBvDuUZ0+sBK*-
z$f^}6^{-t~|NoYd8|5pHELY5q__AJW`bpP_=^oMg{AJOvB769zY_sy++;Q;2N`J3C
zGUBg47`7KZ;@PqHS^6DowR?t7<)%J(I{)0?=eK4$+I|(?)uO4<Somyt<A%ob`D!;N
zJe>J4h;7SO--9iS?nZozaB}W`ZSy8$hJ1JEhI0Y0e%xk?;N&(J(*G`a%=6%cz9uHS
ze+F|lFs;a)t+d1VX8&oPhTW?^-q`4!Sa<pJW$T3gFB*Y$c6~d7Ts|&*mf^#!6`<zL
zd0i&#sab5actt4dyKZeil__raTTeup$MM@=n-V8G@fD+eWCwFjzn;FG@2p*X0HFFT
A`2YX_
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7f0a92ab188b5d64b94c2232b3d730ac7e0a0441
GIT binary patch
literal 890
zc$_n6VlFdiVv1Y9%*4pV#K>#F%f_kI=F#?@mywa1mBFBKwIR0wCmVAp3!5-gXfTY!
z!NcV2XeeeN0^+dq@cQPL=9MI7<|%|_rj{Ej87P3nxp*Xf^Q$s*auOAE6#_Ez@-p+%
z6-rWzOB8^5Weuc3YPfksf>V=Ai!w_p6<qVuGxJhYi-5`uO$>}c(#$;C5dqG@8L2rr
za1%m+CV*%Spp`|X#U<tWMI{-Pnm|Jh<ivS_IxP*&j0}y8OwFUjd5u6^V<^`^(NNw%
z7Gkbgl3oGCKqI}>ip1Q4oK(H!{9J=3MkVAhU}R-rZerwT0E%-lH8C<W>}OeSEN60g
zt>Nx}4;J?=4?SyGHFx66_v@B1ZakG>a9}cPka^RF`%h-LZk+ctCt=ylpnSb~%^w_0
ztIj_1@wMT9&>B2r<F*AiN^h1=m)P`W$_4RNKAct0t`#dPWjh2KRrAHWZ%W|r-Wz1D
zZPS-|f6^PZhWc3vWi_0#A3tg=W0KolIJN!Rto1=&OJ`oZ_aQ3t#zoQ97NyU(@GSS7
zEm{!0t!~}%yQ??diDOTx+OycB!E0`Whtj=ghk9(!3ZDCv<9*~~X6^YoKHKh9869uk
zyk)JD@gYUceP34{&idj!@5o8Xyhm;}yhS1HUe}`QFV|{4EO>8tT)JS=^&Exw`{fhO
zKAqKMVrFDuT&!oH15OCC!YoV%3<mNbrZS6!fmnmchxd%p6?+-?_BnFK+USTHuK1d>
z6fIRTg96e)-oW0aY2Kr%pfy*fEP1Bhw=(pwYHdJB!`g*n&ir-8k`MdSpV`m(wb7wH
zPc+mtJ!ECei$j-Q&Nz3*l+(3*|ME(O1y813ymI`z@aKze^GtN-D16jX3%HQ;>6PK#
z>>XZjZ(g?1yW2X~bHx$s9VdQkiD$2{IP)Rf=>I#>gZo6&9zQpgTyyg7o~YaT-&E_k
z*7i<#;i)jI-C&ttYNBP@_JZY|%nKhs3O{z}QI_G0mB;NiN=bhC?(3v*c4?_0$Nlw-
z)|)-E+SApuxk$9v{@&eWxBio>I*(q|ohuo=T=0GE^R4yjx~zWD2?wN)^=$esZFI}w
W-6R{wNr(O_=<an@`g?CiaVG%o{9=y)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bf4b8cd90de1728c8f85ec9db5d17a5d82f56f87
GIT binary patch
literal 762
zc$_n6V)|y##CUH3GZP~d6C;lSFB_*;n@8JsUPeZ4Rt5tBLp}o@Hs(+kW**k0#FXSj
z137VCLlXl_Lo*{oBO_DuC~;mR5Z4&WHIOotFc5?2;4d#P*GsKP%q_@C)l1IL1zMzp
zYyl%H19KB2KLb#li>Zl`k>UE@y?b6x5&0SVXjbIQ;x*;IbK+fYRi0@}@PAr*Ywwi*
zI>mO20_%_D{Qhrq)|H`*)tUXrvj^_;PBUnnJM*hmBfI&UYni0a7EbZQPj2;_cWy1Z
zJj-n%3rqR#4}xOHO_oY5U^G)WVbJ;E*T#jvKG&SrydfmwXlfMlXzlcLj=BB1$rCNC
z8IG<^DQ69IHa{DqAF@Uw`B+RK+eP1?MkZ(0lp6m@Q*yZr#8=7joJ>Fe+4R7yL~dJ)
zy-b;(md!Vxy65xLdEaN`>4fa~QzaX4J~`vwIU$bk@2~8&eth4`^V7j822To^|71=O
zK6QaDwe-yIyZq0R);4T!n`m@=g+s&rBGI=enV1<F7#9Z`_#1EnLr_+jg~@=yKpw<Y
zW&wt3gNRna9X^LLr3E5FCwx||y7KFQenP#0B1nNCi<E&xlUSl&L1tcFW?s4xO2DJW
zDl;goMNWNP`hM}H2Bw=rA08d+{*(HUL)XgPw|v8v$?M*q_-*Sdn)g~${CUKGy}uS_
zUI`1AyxX?ogm+7>>0<YLr8C4_EM^|t`l|26%$-6vKeVVB=E)xX@kys$pu9$_-{d*l
z&mGnoFU;+>?h_8M7EL%W(NM8s^R+Tj@%v|W^WMM6ITxu|U!K62(Hj{dWUNup@KJZ;
zUET$JALX@+1DUl87OoH8S5xJj6x$Sdm#0VQ*kiUy7wyFvduCd^5YFtKcqn7_SvQ3r
z^-iYuZtk3PwlYMl_<Y2%sLVMN_OU64S}dOUPAT-2+m)^tv3}B8LFY?N1df`!e0(mv
S?DeWYInj@~8Qios#{dA$-87*9
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ab7f218ec9ef36cc3c2a166fbbac1eec73a32487
GIT binary patch
literal 918
zc$_n6VxDBs#8kC_nTe5!iIK;EmyJ`a&7<u*FC!y2D}zDfYC~=VPB!LH7B*p~&|nyc
zgNMo4(NN4l1jJ$I;q}cg%_~XF%u@)<Of5H5GEe}CbMZ*}=2vCr<RmKSDg<Qa<z?oj
zE0m-bmnZ=B${I+6)Nu2N1g9pK7G;)HD!AsQXXd4*76FwRniv>?q?viNBLbX*Gg5PM
z;3k9sO#smvKr4$%i%ZJ$i%K#oHGzg2$cgg;by^yl85tTGnVLt5^BRG;#!#+-l%a%y
z7{pxu^73-M)QZI1f}B*n<osNNCPpP>&oi<zFgG#sGXTZ8n3@<F8Ln#0);x66VD_H*
z?}b!48zkoPJ7#=Wj^Xh)JjE%`khUv8-ZAyBzfaGN+&B5s8(X_<j2}23@xCk@=`W$J
z8uBqR<B#sG_|l%|v)-gJeOWqtV%L@bvsUT0zPnmENqT04M?9a~Ww(_0jfZ}j@(b`>
ztuFp*>63Q+>$Tf9&y!Ycx~=dsK+EjoY|Tdrv(HTQ{kHkSlqYYF6icg3wZ8E7M6Ob&
z)wTzDZ|?k(SSy^+<evQQX!DaD>q8~@3whkcx8LHMYEWG&WLvM2tDz;KxBP@o|Bk(P
zy&LMYi|%->n02st*A>T>4^^LTI5Zr~UlDML!F~H}Vb#A14MP6s6nVRP^6h;-Ez)LU
zW@KPo9BAMVP64vQEKCLr2J#@LG7B(N8$>?5XN<1c%ec4Cku%mtN7Qh|*PNvWiXa7o
zEK&v%O=5|91&}B-LJ4@(6vqq-YlaOLMG+CVAGp_D`rfbmQ1wK7=`y3mn>&2>yf?X2
z*<2+kU~uhjvwARt^RZV6U3=ai{>H<1*4U!v_Mz?8ryXMsW>)Jm+0UKw!|(Y^gF{o5
zV|jA_TuocIs?XRsCHZf$=yNTv3t_kIo%2@c^exGjZom2R__^yA$L1za`FG{g_bcZF
z&P8b`Jg+wpU9|jQcdW>P)Y7LycHiTEXBy@&l}QMBZ?$YTe-dZD{*;p!sx_U8<{j96
z-QjlK83zB|U#`uZ-nPv1_UFwnC)LgrIPzA`?Tt!T(V-nits>`Eg@^9?#=*SNHTz-1
k-0$ao>XvG5emt$q;y3e?Gi~Q3_-ZGs^P715zBz3+0OZePO#lD@
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..afcdc004cb4a648d21cf3d614b2812f6d1f73d2f
GIT binary patch
literal 736
zc$_n6V!C6{#CT)@GZP~d6C<|)FB_*;n@8JsUPeZ4Rt5tBLp}o@Hs(+kW**k0#FXSj
z137VCLlXl_Lo*{oBO_C@C~;mR5Z4&WHBdHGG?0hrkf_j0)GNr$%gfA5H_}V3NX#wB
zN!3fv&js43glrQdD+6;ABR>OBoQtW6k&$7pujszk57H~OmQ3{f?bm)Jpz*`?|3~|s
zF3C$S-D3Bh&C&F;wwS=5`90q|r**Iw8+xw0AIA4%zD8d6-jJou8PDu4=Po>^*3%MR
z_j!)u$;;Zzypdd?lU>-kXBK9AsVk)%7g*ZucHcuXadrB^m*2K6nVzGduJAIurReR&
zGh$iC_o|nEv=FiF3_8`_#4l*TQ+9j@m(ujFkDQ|(%%1-<IR4$*Lle%iYF%079HDeE
z&0Qtf{oWtzv?$r%X)mXo@7t%ul_OJQsiA*GcX#BI8!}>*F?_X8BzE5I_5ESUXmoWA
zYv=6`h5^QFl225Kg^ITv*4lSiS&z$B`%cu?@JAmu3r*S1#LURRxLD6X$AA+Ul(NDs
zOa=_#P?c3?kuVTz5YZ~Q!{<<@v_M4YgwLu~SAHGPPpC(WJ7!Qo_ODv$FuR;rxn}pO
zUlwv#i+9fMRWA(EP;<*#c*6Fxt>fAWhgKDLaX;=%kiE}%h5wYI@^6_buU^*mr_1Zx
z{kq8)`;lYW#1<#Xq(2>(li#<rI7d&qx_-j><^Se?d0PL%VBXD{*1o?~7XMrDR-iEF
z$94G<mYlOs!!LfUTscR4=iAAbxm?9f?Ud^?{?v!xUby(sL0x0py9KYlJf3%b_QQk(
z^WC33+s=yZ;P@q!*pz-N>VEBG2C19z-<9_6%R6^hQqoY~_(7iGtRwR!{%>+t?hD-T
z@pgpXTU|SK$#c6tyLUf&A!_l}OjvaJ{_HhuCd}3A)b?s$T%oz-?d3qp_o0cm<C6jb
D>Rm1R
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..69cebc74b2059789b1fda3c669a12acf6352d401
GIT binary patch
literal 892
zc$_n6Vy-Y~VoF%R%*4pV#K>*H%f_kI=F#?@mywa1mBFBKwIR0wCmVAp3!5-gXfTY!
z!NcV2XeeeN0^+dq@cQPL=9MI7<|%|_rj{Ej87P3nxp*Xf^Q$s*auOAE6#_Ez@-p+%
z6-rWzOB8^5Weuc3YPfksf>V=Ai!w_p6<qVuGxJhYi-5`uO$>}c(#$;C5dqG@8L2rr
za1%m+CV*%Spp`|X#U<tWMI{-Pnm|Jh<ivS_IxP*&j0}y8OwFUjd5u6^V<^`^*-+6y
z9%8OUg<hgw0mMinz0``t+=84`z2y8{gC<5L<WOK_WngY%<Yxeib1^kBGBO<7m3LwL
z)RW)N7aU@0kP`H&_I2{nUj5(L`@Ly~ZCtC}vI&L1rkuW4D>UDUZQinl48oQjO1}?x
zSSpv6sasvzVe^YE_VuTU(K9a;uk{JEjGe7@V}e?aHs`~KkxBn&GL$@NTAdPgVomqf
zj9qN0;#=+rGtE@_aLhRWIA7i>_3Fdiu1_wA$fdUb5^z}mNTp3p)pt=-+(N!KgW1m%
ztrN2&lit5=Ei;NMn9H0OWYoD<bfwK!&;KhLkLYw{zS_7uy@>J4Zi)MkE;ipP7Txb^
zyu)L&y6Nqvm*-+M7EQNa>-+tEK(ozc<<nukKL6g_@onJPCUo+y9{<$_r+L?HGV<d2
zj`>_=VrFDuT&!oH15OIE!YoV%4B$|eRc4Ve5Ni<m@SZWcVlU&~K1a@28y!)@6<>3f
zqNOWlP(YgGGsi#O=Bt{zyYfrQ#mAiYGTJyUTzlwj5<2D25|K$(=QS0Tdu;hvIxiHx
z?@{LH>iIqC%>);X<9WMSjMZGPeS1^hvpFDOmhy?*thy&V*0z?cbvk&oT*T|<jCZF)
zRb5uzVL1K4cD42@?R)Bia|HJ__9)Cz;tum&c-~Mba^ecnq}S;W_cL2chnLmWzbt-Y
zknhR7=GqKt_o6J$y&qlYvrPZX+_Z4wa-WGJIx@fZtNJX8_?I!!lb=;U<bY~-a!+8n
zrfz@U&z{xGGg3k>@tG{h+Wzrx+pP_mCchG0LUJEZ5&z?{;rIrt&Uv!EpDV9*m>&Md
T5&1qS;fQQqQ)gyzgVsR+ON~&8
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d3d88831acab8afe2ee84f58dde5946879148590
GIT binary patch
literal 736
zc$_n6V!C6{#CT)@GZP~d6C<AiFB_*;n@8JsUPeZ4Rt5tBLp}o@Hs(+kW**k0#FXSj
z137VCLlXl_Lo*{oBO_DuC~;mR5Z4&WHBdHGG?0hrkf_j0(ksZ!%gfA5H_}V3NX#wB
zN!3fv&js43glrQdD+6;ABR>OBoQtW6k&)pGYe3$o<e-JYX7?|j34Cv~;LwwGivleb
zqW?{+=bTdZ;B#W(EvwGHiWOViH!>&bUC3zfZ(W%C+bcWgLehcO){KiA0=+MVr&&E%
zq_(5<=CVVLGj~U?ZK;)Q4tg1|=EANDk&?+}hMU+l6MvbUdhJ=S^UcQKfnVc#b7Q7=
zbLYREQSkrG<XMffyW;-cbK<+ua-^Kq?4}uCn!NUfB_%D~Mt*PhNw^gHe-4b^_4U?v
znZM5~w#Xb>#ptto@8jPbGs?Vm+$F64%`y^V)1P!*Xr7K#$}4_PzI_vKy|nVHk2+Gp
z*7v`ugku|1pWEI9?c1&G8yoyT?p);{%oF<C=SRWc(_xIvOw5c7jEnUQbPPCwK`ATD
z!eqbz4pmuY76}8f1`(}-JA4jhN()4UPWY@^b>-Iq{e*h7xMKzdWKC60-PiePQF=G>
zS?*p;<eKr9UD9$_jY({l*i;`K{@9LHf?5oA8#c`6`tphK+%NWq+iT1`-<@XUOLzOb
ztMbX7%hh&_yXzJo*#7sG%z|hcOW#xTet9^gIf(pzRVuNxZQs4cOVlKP-hK6Y%VOgh
z51Tn!U0!iZY`@}DoR`Ctx1Qn7DxOJiWG9HP3DDLkJaGTf6F#mp#;vvPW%`e9N!Oe8
z_kMD3<^IHSeu0g2-u27c6)TS_zle+3=6z|p&>xF}z}NYo4)J=usk7*k|0dkz^{TDf
zw@L1p5t~TK#^w_S;WLj+<nwvadS-w4_wF~77aKK+ExGQKz9RMRC#S~(%dc;<R1X0F
DmIp3Z
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7684ea73a2276cea826380d98000000aed6cf101
GIT binary patch
literal 892
zc$_n6Vy-Y~VoF%R%*4pV#K>pB%f_kI=F#?@mywa1mBFBKwIR0wCmVAp3!5-gXfTY!
z!NcV2XeeeN0^+dq@cQPL=9MI7<|%|_rj{Ej87P3nxp*Xf^Q$s*auOAE6#_Ez@-p+%
z6-rWzOB8^5Weuc3YPfksf>V=Ai!w_p6<qVuGxJhYi-5`uO$>}c(#$;C5dqG@8L2rr
za1%m+CV*%Spp`|X#U<tWMI{-Pnm|Jh<ivS_IxP*&j0}y8OwFUjd5u6^V<^`^*-+6y
z9%8OUg<g_g0mMinz0``t+=84`z2y8{gC<5L<WOK_WngY%<Yxeib1^kBGBWJba<Tu|
zQMKRl&xu7`<=dU2qs}qa@n6V|b(BA-<F1vQ`PosVr)s8$>x_jg+$C>XPyH01cyDQ!
z-N!Ymdy;CU6K`^|YkThBa4|J$flIDPu;Q1KS7IiLFFDlxb4JBoKiM0r<W6(w<aDYE
z_AcI+G-uz>nhE}KD#cThr~itdoVEA*x#Z7FxO(TdIi$I1>2hD1A}@0<Ur_Po>gD$=
zD}pcDt=MoYd8+20kL_wjn~uwgUT{!sP`nY?q3;%5u5$a8-Nt>#eZ2UWtT1$|4JtM|
z)j9WYVtb1Ej`bF9DV}po58Riko^t%J?iN1h)hCX$OqB}hk6vK^PWN@$_0xfZEA7kJ
z{jXePVrFDuT&!oH15OIE!YoV%4B$|eRc4Ve5Ni<m@SZWcVlU&~K1a@28y!)@6<>3f
zqNOWlP(ZfF-%4v%H8wP}?VEjHLi2Uc71NnK=}n8aKDcOc>Ds$phM$+qe>LcMo^Rps
zzjXfbQ-8|}SE{dF#4kKEYn$IH^Sw#}ksk}W|NYf6ULGmGwwpib#=S=hC$IE&o@Sal
zdHv(`Tbue7bw4cq)p*I;`9fBm%99<_o+w+2``LVqT76x5uD7D1W5S>3{wx*B%ffGo
zR&1F3tmv>$NZ_4D=InJs59cbpd~;>#@BhYg?s8c^j@To$?v(Z)?GJXVq<>60J7Muj
zt9$299ay|R_lton*EY}AjZE>{CP(*J`W~roTl#i?9-r;orB|fAGt^Bv4xSNi)9{zt
W_hVfOtIpyBF5Nc{z7T9mm;(T6g;+@d
new file mode 100755
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/generate.py
@@ -0,0 +1,99 @@
+#!/usr/bin/python
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import tempfile, os, sys
+import random
+import pexpect
+import subprocess
+import shutil
+
+libpath = os.path.abspath('../psm_common_py')
+
+sys.path.append(libpath)
+
+import CertUtils
+
+srcdir = os.getcwd()
+db = tempfile.mkdtemp()
+
+CA_basic_constraints = "basicConstraints = critical, CA:TRUE\n"
+EE_basic_constraints = "basicConstraints = CA:FALSE\n"
+
+CA_full_ku = ("keyUsage = keyCertSign, cRLSign\n")
+
+authority_key_ident = "authorityKeyIdentifier = keyid, issuer\n"
+subject_key_ident = "subjectKeyIdentifier = hash\n"
+
+def generate_family(db_dir, dst_dir, ca_key, ca_cert, base_name):
+    key_type = 'rsa'
+    ee_ext_base = EE_basic_constraints + authority_key_ident;
+    CertUtils.generate_cert_generic(db,
+                                    srcdir,
+                                    10,
+                                    key_type,
+                                    'cn-a.pinning2.example.com-'+ base_name,
+                                    ee_ext_base,
+                                    ca_key,
+                                    ca_cert,
+                                    '/CN=a.pinning2.example.com')
+
+    CertUtils.generate_cert_generic(db,
+                                    srcdir,
+                                    11,
+                                    key_type,
+                                    'cn-x.a.pinning2.example.com-'+ base_name,
+                                    ee_ext_base,
+                                    ca_key,
+                                    ca_cert,
+                                    '/CN=x.a.pinning2.example.com')
+
+    alt_name_ext = 'subjectAltName =DNS:a.pinning2.example.com'
+    CertUtils.generate_cert_generic(db,
+                                    srcdir,
+                                    12,
+                                    key_type,
+                                    'cn-www.example.com-alt-a.pinning2.example-'+ base_name,
+                                    ee_ext_base + alt_name_ext,
+                                    ca_key,
+                                    ca_cert,
+                                    '/CN=www.example.com')
+
+    CertUtils.generate_cert_generic(db,
+                                    srcdir,
+                                    13,
+                                    key_type,
+                                    'cn-b.pinning2.example.com-'+ base_name,
+                                    ee_ext_base,
+                                    ca_key,
+                                    ca_cert,
+                                    '/CN=b.pinning2.example.com')
+
+    CertUtils.generate_cert_generic(db,
+                                    srcdir,
+                                    14,
+                                    key_type,
+                                    'cn-x.b.pinning2.example.com-'+ base_name,
+                                    ee_ext_base,
+                                    ca_key,
+                                    ca_cert,
+                                    '/CN=x.b.pinning2.example.com')
+
+def generate_certs():
+    key_type = 'rsa'
+    ca_ext = CA_basic_constraints + CA_full_ku + subject_key_ident
+    ee_ext_text = (EE_basic_constraints + authority_key_ident)
+    [ca_key, ca_cert] = CertUtils.generate_cert_generic(db,
+                                                        srcdir,
+                                                        1,
+                                                        key_type,
+                                                        'badca',
+                                                         ca_ext)
+    generate_family(db, srcdir, ca_key, ca_cert, 'badca')
+    ca_cert = 'pinningroot.der'
+    ca_key = 'pinningroot.key'
+    generate_family(db, srcdir, ca_key, ca_cert, 'pinningroot')
+
+generate_certs()
new file mode 100755
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/pinning_root_generate.py
@@ -0,0 +1,59 @@
+#!/usr/bin/python
+
+# after runing this file you MUST modify test_pinning_dynamic to change the
+# fingerprint of the pinningroot
+
+import tempfile, os, sys
+import random
+import pexpect
+import subprocess
+import shutil
+
+libpath = os.path.abspath('../psm_common_py')
+sys.path.append(libpath)
+
+import CertUtils
+
+dest_dir = os.getcwd()
+db = tempfile.mkdtemp()
+
+CA_basic_constraints = "basicConstraints = critical, CA:TRUE\n"
+CA_min_ku = "keyUsage = critical, digitalSignature, keyCertSign, cRLSign\n"
+subject_key_ident = "subjectKeyIdentifier = hash\n"
+
+def generate_root_cert(db_dir, dest_dir, prefix, ext_text):
+    serial_num = 12223299546
+    name = prefix
+    key_name = dest_dir + "/" + name + ".key"
+    os.system ("openssl genpkey -algorithm RSA -out " + key_name +
+                 " -pkeyopt rsa_keygen_bits:2048")
+
+    csr_name =  dest_dir + "/" + name + ".csr"
+    os.system ("openssl req -new -key " + key_name + " -days 3650" +
+               " -extensions v3_ca -batch -out " + csr_name +
+               " -utf8 -subj '/C=US/ST=CA/L=Mountain View" +
+               "/O=Mozilla - Pinning test CA/OU=Security Engineering" +
+               "/CN=XPCShell Pinning Testing (untrustworthy) CA'")
+
+    extensions_filename = db_dir + "/openssl-exts"
+    f = open(extensions_filename, 'w')
+    f.write(ext_text)
+    f.close()
+
+    cert_name =  dest_dir + "/" + name + ".der"
+    signer_key_filename = key_name
+    os.system ("openssl x509 -req -sha256 -days 3650 -in " + csr_name +
+               " -signkey " + signer_key_filename +
+               " -set_serial " + str(serial_num) +
+               " -extfile " + extensions_filename +
+               " -outform DER -out " + cert_name)
+
+    return key_name, cert_name
+
+prefix = "pinningroot"
+[ca_key, ca_cert] = generate_root_cert(db, dest_dir, prefix,
+                                       CA_basic_constraints +
+                                       CA_min_ku + subject_key_ident)
+CertUtils.generate_pkcs12(db, dest_dir, ca_cert, ca_key, prefix)
+print ("You now MUST modify test_pinning_dynamic to ensure the xpchell debug " +
+       "certificate there matches this newly generated one\n")
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bccfb21155ab09290509ada0a6b70c4d53e5ced5
GIT binary patch
literal 1053
zc$_n6Vv#gxVrE>x%*4pV#L9GI!v0$Zylk9WZ60mkc^MhGSs4r(R~vF0aI!Invaks=
zg$Bbo96U_Uj)r0eA|MVs53g^2X<kWUW}ZS=W@@>il7Rw9oQp@&H@_+~Cnr%sS0NxX
zFE2AMU7;kkxI_V{SJprpq=uVEBsev>v?#NrQo%JZJu@#gwFs!p(8Rz9B+bmD9TDIh
zoRON712-WAXab1V09sj8T3k||UsRG&sR=aHKu(+&sMFHW%+TDx)Wjr8oYx4%HHLDB
zm~WaGm5`%@k(GhDiIJZHD9**y#K_37>g>T?zi-dKJa1;X`ZC68XZe&iJ~Zm6J|;8g
z;-$=gZ?vRceRZmNzdsfVS8YDBr*P)Uq-l%7tP5s`-%IKV+`sbm!%g{f*@^|V7*#Xl
zexFg%n9&k`QqK9Y*onl`?<BTQy}%o8cS6hEM@lc*=99$-MS;CtGc@^cEl)r4^&H18
zy$7u!I>zgZ6Q0Zbd20AR^w5N#JFFM)?^gU|_2t@KcmJKQ&#OMqVpjWTw^vQ)smL(}
zrScuA2hK>${+4oZs)Tm-Oj*s-f_k&#@6UUvlqNNybyu&PdyT<;&3OS=#cv4-JoTGU
z%-*;oO=;p`p<tbDiQEtNw6QjR(|k~pc46K2<<BOZ6IEwoW@KPo>}23zzz+;vSz$)T
z|17Kq%s|S34<x`35?}!)?luEi5TB1lj78+bd&cOBy^MSN964icbVLnTe9c*kmgt#5
zfg3qxf8ATV4_Pl4{CUg1T1!gld;j(W32e1L+#WF`L>+lF^XIxpmaiBKf=e>YU$H*6
zZF#)Ayma$#QAwVwPxt<Cd~eyzoow*dBeu@If9-2`)mevL&3bT4UD{=D_1=%4$|GgE
zzx?=bcqc7!HkV#YM6id)g}?)U8l?+o7Az0>tvolSvO4K_`<Wchhjtc+jP`!qpczqn
zp5tzd7W<XR4g1aZZ0X|OTX^B(S~1yaXVfIPg^#XGKXsfZO0R6=H_qS5>YWd2Q&yjC
zNbZPyP|DALg_Wb`hik|EWm%r00blQz2Y%LE<?c80d(7UCzZl=mS(v=b@s@#G_JyDS
QVly5e?A($t=Wp^o0KW{0TL1t6
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/pinningroot.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqzcG6+9uf056Z
+dyemAZbNDiKx4TKIe8YcnNHSaf7sKhtFTSx7DffjElclg8S8cZnJYpaiVjtwm1fe
+YoxRv6nr4bJvnQZzESoBJWle+8wkKJiEV8keQ+MWyGHL7hi3ldANVz7IKkdMGi5j
+PPI48CEQvYqYKQ/ap2fE9c4Iui7ghVQsM69zYOcc/OUx71XCkPm4O6O/iyHyOvTW
+3UdPuevPJedqAybxPr0mLOUUxiAid7hlwMwYm/ZkwZUYK2uZHSnLES6bX9+e4SJm
+GpCFuo0eR3ww3ymeUNUX2hIQ5U6QcweBuGYikcMSUyy2YQvgvIYFgfYp4HRm0K63
+p+aQzhUnAgMBAAECggEAYnCBhg2fz2Z8ksAstq1Vx0qtTk2W/Tgwvs7W0ulKBbxi
+yTcoOqebRWCNn05pNZ5XXsyWOmtuiIDPTJkJfBf1i8AhQdiDHhA3YD+6kgaW6gQH
+msapX+sKV1gXnRvVXQFXzkiJI33SZ5bzQzid9ZjXxbknxnhr7b3rvYVZQIhlefoM
+nZbUMS5iyZSeJ13Zj/GxGagK3OwoV4tSG1BbE6at+uNgC0MJuAwBiGvWdCTPPiWc
+j+IgvE8V/7ZyZjVZMRj/Bwu6M9L6X3H5N6P7yZ8kyvuZBm2fzi/ZsDetjfylRGXd
+H7qqrSJmU/uJC89JBtBuplppnfpx7z8VWzfzVkBmeQKBgQDXQPgad4+WSXAmHfCW
+UZzwM5BImL/TffXtsZaA2/KL1FJ9qH+oIyM/8SoIipCDO5iw3hVyJoDcvgAbQLfw
+5B0HhWnLmPvP5p5K6e/hfs6IeBM4TFqiixwNMbsAMaDcGeXm6ifP7QrRkNrFatd/
+ZnX+noSI2avoKP5Ta01fu4CLewKBgQDLIsXa437RZHzlKzcm9wqSm693ctiwyyzo
+ku31LzJxzR8ZmUKquVQv8gEkC2rejQHA47nZ9a+JRkP+O4TAwFvQlk2fE4RQqSNC
+j8C9IJbqKv8pd12MLg4PjxYsGOdJPawLKDBAtAFIxcwPbv7z87AYUwJHsA4NGBxM
+D1o0Uf5nRQKBgEo/oNUQVLkUT9j2Dtzq/eVlA+nmtpRvKHt6/F0qgTl2XZX2n0IS
+DMCroUIc+cgqsHqhwGgFnAGIkGTWKByxssm7XUjbVlDaTdOtag8wPHGaaZbLz5+t
+uFlcxBJHDCOf00uZjW4NZ+PtwWjDd938K8tORo0l+EQ2j7Oama/h728tAoGAMhLJ
+SPLJQR6PNwKXHtDI12jvMPereLEsycvmQok22xygLPQ9nc3/da4nH9Z8qo2BwCWi
+m5rXgXRDsHjFeaoxN9LFIZBzDlsTKQY8kaJl8SVWLseQ1MxJhQZVhdtBsCk2rq1i
+b6CvrFutuKQ4zrPkVaqopjk8zXeDCjDCoKERoC0CgYAfZrMB70Za9/ha8S00HhHW
+SZ7pvFFZuWrpGVNIK2DmhUFfl+T0w+qxyVNIJ/oHeMq7jy0HDbwYBTbf6+6Q6Kur
+hKl2FHYU8kg+Qt5DT9yx0FLM4xQ8E4IlR7bF/3ZQl+qZGhuxfX8LqSHY7u3IYqpX
+qt81/FWJVd3bd1g61cbBog==
+-----END PRIVATE KEY-----
--- a/security/manager/ssl/tests/unit/test_sss_savestate.js
+++ b/security/manager/ssl/tests/unit/test_sss_savestate.js
@@ -1,19 +1,22 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // The purpose of this test is to see that the site security service properly
 // writes its state file.
 
-const EXPECTED_ENTRIES = 5;
-const EXPECTED_COLUMNS = 3;
+const EXPECTED_ENTRIES = 6;
+const EXPECTED_HSTS_COLUMNS = 3;
+const EXPECTED_HPKP_COLUMNS = 4;
 let gProfileDir = null;
 
+const NON_ISSUED_KEY_HASH = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+
 // For reference, the format of the state file is a list of:
 // <domain name> <expiration time in milliseconds>,<sts status>,<includeSubdomains>
 // separated by newlines ('\n')
 
 function checkStateWritten(aSubject, aTopic, aData) {
   do_check_eq(aData, SSS_STATE_FILE_NAME);
 
   let stateFile = gProfileDir.clone();
@@ -25,17 +28,21 @@ function checkStateWritten(aSubject, aTo
   do_check_eq(lines.length, EXPECTED_ENTRIES);
   let sites = {}; // a map of domain name -> [the entry in the state file]
   for (let line of lines) {
     let parts = line.split('\t');
     let host = parts[0];
     let score = parts[1];
     let lastAccessed = parts[2];
     let entry = parts[3].split(',');
-    do_check_eq(entry.length, EXPECTED_COLUMNS);
+    let expectedColumns = EXPECTED_HSTS_COLUMNS;
+    if (host.indexOf("HPKP") != -1) {
+      expectedColumns = EXPECTED_HPKP_COLUMNS;
+    }
+    do_check_eq(entry.length, expectedColumns);
     sites[host] = entry;
   }
 
   // We can receive multiple data-storage-written events. In particular, we
   // may receive one where DataStorage wrote out data before we were done
   // processing all of our headers. In this case, the data may not be
   // as we expect. We only care about the final one being correct, however,
   // so we return and wait for the next event if things aren't as we expect.
@@ -67,25 +74,35 @@ function checkStateWritten(aSubject, aTo
     return;
   }
   if (sites["d.example.com:HSTS"][1] != 1) {
     return;
   }
   if (sites["d.example.com:HSTS"][2] != 0) {
     return;
   }
+  if (sites["dynamic-pin.example.com:HPKP"][1] != 1) {
+    return;
+  }
+  if (sites["dynamic-pin.example.com:HPKP"][2] != 1) {
+    return;
+  }
+  do_check_eq(sites["dynamic-pin.example.com:HPKP"][3], NON_ISSUED_KEY_HASH);
 
   do_test_finished();
 }
 
 function run_test() {
   Services.prefs.setIntPref("test.datastorage.write_timer_ms", 100);
   gProfileDir = do_get_profile();
   let SSService = Cc["@mozilla.org/ssservice;1"]
                     .getService(Ci.nsISiteSecurityService);
+  // Put an HPKP entry
+  SSService.setKeyPins("dynamic-pin.example.com", true, 1000, 1,
+                       [NON_ISSUED_KEY_HASH]);
 
   let uris = [ Services.io.newURI("http://bugzilla.mozilla.org", null, null),
                Services.io.newURI("http://a.example.com", null, null),
                Services.io.newURI("http://b.example.com", null, null),
                Services.io.newURI("http://c.c.example.com", null, null),
                Services.io.newURI("http://d.example.com", null, null) ];
 
   for (let i = 0; i < 1000; i++) {
@@ -93,12 +110,11 @@ function run_test() {
     // vary max-age
     let maxAge = "max-age=" + (i * 1000);
      // alternate setting includeSubdomains
     let includeSubdomains = (i % 2 == 0 ? "; includeSubdomains" : "");
     SSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS,
                             uris[uriIndex], maxAge + includeSubdomains, 0);
   }
 
-
   do_test_pending();
   Services.obs.addObserver(checkStateWritten, "data-storage-written", false);
 }
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -12,16 +12,17 @@ support-files =
   test_intermediate_basic_usage_constraints/**
   test_name_constraints/**
   test_cert_trust/**
   test_cert_version/**
   test_cert_eku/**
   test_ocsp_url/**
   test_ocsp_fetch_method/**
   test_keysize/**
+  test_pinning_dynamic/**
 
 [test_datasignatureverifier.js]
 [test_hash_algorithms.js]
 [test_hmac.js]
 
 [test_sts_preloadlist_perwindowpb.js]
 # Bug 978426: Test fails consistently only on B2G ARM
 skip-if = buildapp == "b2g" && processor = "arm"
@@ -32,16 +33,18 @@ skip-if = buildapp == "b2g" && processor
 
 [test_sss_eviction.js]
 [test_sss_readstate.js]
 [test_sss_readstate_empty.js]
 [test_sss_readstate_garbage.js]
 [test_sss_readstate_huge.js]
 [test_sss_savestate.js]
 
+[test_pinning_dynamic.js]
+
 [test_certificate_usages.js]
 [test_ocsp_stapling.js]
 run-sequentially = hardcoded ports
 # Bug 1009158: this test times out on Android
 skip-if = os == "android"
 [test_ocsp_stapling_expired.js]
 run-sequentially = hardcoded ports
 # Bug 1009158: this test times out on Android