Bug 787133 - (hpkp) testing of internal storage and idl r=keeler.
authorCamilo Viecco <cviecco@mozilla.com>
Fri, 12 Sep 2014 14:59:37 -0700
changeset 205894 7b3ba487c01b6c55a4d290b1f1ab826f42c37eec
parent 205893 605c11a57482fa7c59dde1ca52e1f2338aa85f37
child 205895 e3da4ca374cf921b5de1f641e19326dc5e2696bf
push id27507
push userryanvm@gmail.com
push dateThu, 18 Sep 2014 02:16:54 +0000
treeherdermozilla-central@488d490da742 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskeeler
bugs787133
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 787133 - (hpkp) testing of internal storage and idl r=keeler.
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 0000000000000000000000000000000000000000..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 0000000000000000000000000000000000000000..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 0000000000000000000000000000000000000000..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 0000000000000000000000000000000000000000..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 0000000000000000000000000000000000000000..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 0000000000000000000000000000000000000000..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 0000000000000000000000000000000000000000..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 0000000000000000000000000000000000000000..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 0000000000000000000000000000000000000000..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 0000000000000000000000000000000000000000..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 0000000000000000000000000000000000000000..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 0000000000000000000000000000000000000000..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