Merge mozilla-beta to b2g34. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 11 Nov 2014 14:28:47 -0500
changeset 221204 b9849b3c6aaad0646b548f7e3d2dd559d8a2b0df
parent 221197 03d5e19bc3b46a46cd8ef7ed48ae750d7972e67d (current diff)
parent 221203 e7f8aa528841d4b63e8f9f1d4ee5a7be630368a3 (diff)
child 221205 90f687bae552338c3e6dcdb404ec6cbd1ccab6fc
push id164
push userryanvm@gmail.com
push dateTue, 11 Nov 2014 19:28:43 +0000
treeherdermozilla-b2g34_v2_1@b9849b3c6aaa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone34.0
Merge mozilla-beta to b2g34. a=merge
dom/webidl/moz.build
gfx/layers/Compositor.h
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -18,17 +18,17 @@ MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/bran
 # MOZ_APP_DISPLAYNAME is set by branding/configure.sh
 
 MOZ_SAFE_BROWSING=
 MOZ_SERVICES_COMMON=1
 MOZ_SERVICES_METRICS=1
 MOZ_CAPTIVEDETECT=1
 
 MOZ_WEBSMS_BACKEND=1
-MOZ_NO_SMART_CARDS=1
+MOZ_DISABLE_CRYPTOLEGACY=1
 MOZ_APP_STATIC_INI=1
 NSS_NO_LIBPKIX=1
 NSS_DISABLE_DBM=1
 MOZ_NO_EV_CERTS=1
 MOZ_DISABLE_EXPORT_JS=1
 
 if test "$OS_TARGET" = "Android"; then
 MOZ_CAPTURE=1
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1270,16 +1270,27 @@ pref("services.sync.prefs.sync.security.
 pref("services.sync.prefs.sync.security.default_personal_cert", true);
 pref("services.sync.prefs.sync.security.tls.version.min", true);
 pref("services.sync.prefs.sync.security.tls.version.max", true);
 pref("services.sync.prefs.sync.signon.rememberSignons", true);
 pref("services.sync.prefs.sync.spellchecker.dictionary", true);
 pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
 #endif
 
+// Developer edition promo preferences
+pref("devtools.devedition.promo.shown", false);
+pref("devtools.devedition.promo.url", "https://mozilla.org/firefox/developer");
+
+// Only potentially show in beta release
+#ifdef MOZ_UPDATE_CHANNEL == beta
+  pref("devtools.devedition.promo.enabled", true);
+#else
+  pref("devtools.devedition.promo.enabled", false);
+#endif
+
 // Disable the error console
 pref("devtools.errorconsole.enabled", false);
 
 // Developer toolbar and GCLI preferences
 pref("devtools.toolbar.enabled", true);
 pref("devtools.toolbar.visible", false);
 pref("devtools.commands.dir", "");
 
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4b90768d2d172703a185da55bf3ab9e619ca6a63
GIT binary patch
literal 6764
zc$@)j8k6OTP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF000^@Nkl<ZcmeI3
zd5mP&b)Ua`?^|l`eWqvMxDH8Clt@vbDa+byfr<^wNo+)bBf*YfIEfL&Fzh7AW+8AO
zC`kTDVj&2USP^Uo5u7-SOxcQLEu>6^t4N9*4rhil(=)wy*IxCOyX5IsRkP5Tkz$a_
zg6IHWo%im$)7|HH&pqcp42u7+?FaS)`+*6*&-Qa)*{+sC`7SBNgE-z+_#?*HTMJ*u
zArJsK>s&`k`KoiQ0M9yj!dm+nF#Ns>@K+w+<;}L<AZs+L@y{UmX>06zj5aDa7EhXE
zw5AxxIfo2GoX(L_5~zYwOcVqJfh<tDRPu|?@i}Ac=Yam3F2FB7_T~xTaHpgYzh<5L
z*=(3r2K@m^k~7Q<S+2<o90F?{IvL^$A66@vevcrIQA(n$^}$C`NK`ISuEYgp;!3Hb
zr1&l1Q^2)1O@P1lCr#d{W!f%D_=L{$j~BtJem|k#AChE-+&a=UCreVC5Ex@HX$nGM
z3m;S}xWWr-P*I2q3Iqg75Y=kL7%HU@QOuj2sZoieG>U>xJI5!0<{RGvZ!iN=ZGPT4
z_o-g1GuKaY1_k|Ahk=G9Ny(A~lWUA~UI3&-Dg`)H6e9zL?z9mINQRJSC_#Zh1p#5T
zN~v7p_Tvjg2N&rXfwVANEo~P<{1Wi*zwb5Rz@Ym9;EPPzYcie{h|eUw{!et;J$n6w
zL4QcEJ7kdMXut`H%X1&Rc3`!}T8k6{z^^#g;*tbElBGx`QBoo&B4EKmtP^JI6;8k7
zUbgBpEaAWkYPHJm9*f0a-`?C!fzF>=fM5F0=lO2-zEg`2e*WU_V_~3TzydVG_^fpH
z_j~Q`t?lh5o%IcdX-*!-<VixN4aR~_QgRib5eTUef%4f<h~igX7&8*XS=?}dDwVtd
zg^CDgkw6dzsB#4*A<!wIl)Uw!xARP6p5;(*${8A!@<!+KTJ~q|IrfXd=l@g!{O14I
z<Ysob6sWIVY5l=tS6e^&!CU6v4}9r@DBWKK_D8MFt-02<ReH@9sd4BaL`y}wzKTJT
zM^$RoGIyUkL{o)m2N%y>CP^|>DaQ1Aqskvg=x&FwQo$BpI7d*gBXPJ+3n8VSM-&t5
z0b#99cwm{g%mqAq%iZ*?<pZ^l;UH(O({T^pb>vrofAYU9z`uO*<^l+9f9jK8d+ql+
z!;JTyUU)2<ZTwAi{`uzRD>JS2O$LJ@xeUk#10TG$g2YPZ8&%GpIZS_Xf%5~66>wr_
zn`fUn@Aq`p>msa0c>!W{r{yz2MG>~&MLIhYXKo%l=;O5Zbwj0HLYosFIf>FK_r3jY
zzIxy&ZEbmEHl~zlPLa8Owet60>8Af0Smk?|{0~>#+>GCQe(j^}?hu=4{`*U-56f2j
z>zn6Znc2B|jb5r57UP4BHIm(JY^A}_z|qA9$L_m>Z-!N#X(wpsINNFR%#$yp;+VYG
z18u<=ADAmV+Tha6-wR(iw66>K`WhxEA;JiH9h`y83TovLx4XsDU-~K!H`j5%e`}>|
z29i|~ib0b8y1ugcjRV#AU;*C^@fW{vl^fZQ&6j6B{n*9L^PAlWW3hQoC6GLDxJ19W
zE(u4DAhXW5xSop1`a|N|PIGanaYEpv;N3C&;iG>tssT!2k_4O^?QtRe!N;`Q2y6UU
z*qFf-f=XwwGDHqL$T&jHFJZUVkWt9|@gp30<VUGozR3DB&mlkf2+yh#0{G!-$Su<G
zjX!*f(+{0}>h=S(4*@whvEWdsxRDv_?qAvIh1M4>O^D^>QiC-a(GH=RYpn1M8#$v`
zC`Ygim-;zK0l=wB#B+~7gEN+(TqW;y*)xYPin#HOcMj9-plWqodlxGuD(NGJU0kP$
zI(8b74ro31EafQVr5||@Cy$-v(8X6cck)gW2Vd*u)EW^BM;5s9t@HP1KXl(GfWO5}
zOujJ4xe?b}gVWu9B21cb%VL%L&mQG!?pW!iw2}<x8~_$e?hGgDA*+KFrsC0CyR2`w
z{b9$X2{MXMaj76ih5<4NQPmnjV+Qpd>J3B~BH|JVNtpF<wRvoL26x~XF4Ndj9UQDZ
z|01_O`8dxT#gnJc^7fED`=d_E!r9YgoeoXye&sFY@Xi8mguK~<i|d_=O>^FMVgXmH
z@WN&nYuzYt#~z|!Ar4p@Wb8LnjD__&L8<K1-&u>vQojvsp8GK&1iIbEbXwS67j*7h
zVsP{%a(036@G*iDXZ)c^Zm;9kS8+#g!NpZBeB&A3Hte!t92c$R?pOg1?cke3&GF*Q
zko1Sa<K65N1>6XEvj^v|?{;rLJj<q)Y;_Z`4xF7%*@^eH;Yx3^`lGQ}3f~n@96RKL
z7D9q`1r~6Ao^uw2oZS0o&Wy%<aSQ_N+6wN{%doWujagJ7s7w;%@^Mr$#60?WmXu&U
zxAd*!<akSOYD1^dpj3*voazt%<V<|Dfc*r;2RE{>&)3EIcH;Z?-XDzsG4f(chP8eM
zLhMZe$4nquY4%uHY;f0G&LFJwM_TI~vC;H)J6ycJ<-3H8VqXvi4q-H|*T%MXkTbK8
zCI|-@4Lh4iYY@iZaOhKKxl+u#V|R<k8jHM^86GGHZ00bu@U3Cahi6JW-%Qjq{p`cQ
zKVzTC;sN`?xrOUm{DU+zV9ZDW=RCpz9=GR>bqH55Rp1l?jAgf%@a>-FMI(7KF+5f9
z^w4tb*fRIresa_b(;;@y!}dD3eiy76XPZMv`TFl><iQ~~R|(I53t=qgsi&!qSLEq|
z=B`q}p+Nfki-|@!Sjp`B3)qjm(cp8Ny<gwy4v#vcM`=0!1NNuBV84w75`e`Kn+!Kh
zvEQND!>;al%vOtjs@dLd;l|>MF^sXcVC^clF^5IqQ~(ZOJTHt8S&D3JbLFM;+-5Vp
z2F|gX8y1xGTf;bqEEs6}&I0x$_YZui5iecqBtPeJ4aS0X2s>5yn9hR9_4M=6btgA0
zmn4TH!5#GyXG#GlV#Qk)>fCYsAXnFSxODmYB>24*cOn?QE2MqYpp6`K5WQVY5Q7jC
zk^D6{WT%Nn5?vepEP&O_B5^DR3T;6+NUS^X?s_y=z%+9Iz{Vi^g{!;$GI}Dw^a|kt
z5L4M805SFx5fW`VbYPxAtIy??E!s(rE0+mpYPjt!F2C^YQ7}_K-!TeGb$3zy7Q$IX
za}!Z*5UyWDOEtX}UjKK4E?i$jz~1wf%#Z=bjxwOHE!uIWfNA9ZflIC7M@^plD(tL*
z>D0tc-Q&I3R}aM0HW<vzkaT;vZkJM)a4d3Me(G6XeC{Qz)*!%*PlXg<EY|-~DZ-A#
z7sDPdD*5NCy@d%&{$8ZRQSeeiuSNTbuQDguTZERe0O)buPK{+T5X&=ydkdH#r*D=+
zdFN_-c*f=9GrCXxeZZ6mQ~TaIriBOvT(WR?(E$$6)sX3s$G`C`&E4_JT05R=_x8WS
z5SR=zcL+1H1TdPbGmr|ICy3@6S#@Uos~vOicn9+*Ptaby&I}-@7Djjh1R?nQUN8CC
zmCg3Y3z#6MZ#D<nd%MF_SpSk@ac-*m17dpBDLk)VGk#u{f?6Oc3BmDlL~nVCelq0B
zwe@k}Q+r-Yux?5Oi?kX^;idFKIH8c+tJt}N;2cut$o3YlwSlQLFh&!7?B|Ia4d{0G
zv3dl&-ZeJ0<zOfYfpeEP9%;6E_ZKihPT%x0^U%Rk;CyScroefotFylz1wK9I2?Q+0
zA;&8b_s&*m1d@6|pv2Uw7uZq2AV$|?5q#G5ySM_I=L9Cl)E5wiM+iU11EZfMpfc$5
zyozaj_%Bc!4jDQqF)Ehf_+_oE1Z4r2RyL~naQM~&CdlcV`B<G<Z}prt7FRH8QTy8z
zV?UkxAPYYeDj)EC6tJ1(L_%<^98oJ62k*TYdk~=Wy?c=*1l?_d-Y%-ULmt=szW2W?
z&p;@|xC02IJxVH+bF9DRZ7escJlW4V5h=<-kWLm4L0w9cJQEe0#RW_ViVr5%8D@jd
zAeGJ-thERsa6;ln!B2TX0Mtq$N=alvy%hPr`||1zX`omNjBkZU?>WPlHg*thR8z#1
z2v({|>U*42FuBhY;_EN(iLII&nAs&na~+HZAP-^&l^Lo)Gq=nwETCHnogB`@inZJ#
z9Y~-oEStR!QLw<Y1yLZGSTEJj*F*W9cHfM9vKZqK7K9jW2_+q&lC%aXNXe;2nQO1E
z@^ohaN^-g$@THf|Bb?*a7ha*;8zK;(l%J2Iz~B%bqyiyvGQd_Fey&p?&S;|62KYi~
z{2bj_1Qn4jpF;K9h>I^!wvUh-%lSm3tfOlz$Af^5wmvf*4%KQRhdt!tJ^`i&25ENS
z$ZVD7P8$hWArJ*Zit);b!daXZB$@W(x6W30{-qTXV-ZRs!hk?2L=c13bb7;46(6tq
zbOxB}JVNKby8AI9!3lI&#@6NtJDcdaW#9IkP?(uTA4K`ei~ipLxY-JUb=(#zsz6|@
z7a<4KIAdc3a%YpJ`35_sx?##>F~EdU7}R}=TZ=Wu`w4cs2#!yO)j+Yc)h5-(2d~1Q
zKv6D*zHkW#AV7r>gd@-E1<^T1!b}~8bYlryn?>RfqjQKq6veCO2{$fd!<c;T5H>0U
z5XA8~Xv?8c5*bI$LC-p*2Vw!~+A528ou!$Xs|8F5iVr4sd%awH;lg!7DNsUEjzfBh
z_Q8tL9zY1jg;8**Ugo)%wh&Sx1LYB6K)Y1o=u(5#Yim;l)WW3l3k6aD;Ku2WwMdf_
z=P6QW{^(n@J3lt513_m8ge2O0jeK?)TV#h?SVm_CA@D7)?i_P*z=gz&M07A0NU}Tc
z;zd>G5WK>a1>w|9y&R<*yPagQS}G0GoIpveHApM4QXri4io!?`F?wn7t1gv91O<iP
z8s;qDbr**N#oEQouM1!u)7wA_!HGlj)DG7`=j>d&PH%h1KMRu{d36@m-h{CLx;BT%
zQv?vT))8?`Si2pW8{$aOF%G9Ky%?mO9GRh=YF-Uyef_E^@dQ&A6a!4`()#Y@N)+4~
z2J(2CK@>==wH{#vR*d%PXqz~+wn!<EN_YXJ90@?-H&ab~>m4l3&6Auz&tSK?*9zws
zW?4Ra2ln(WzEW=+=fzlhC}4Sgg|#nyfuz+&N`(y~zu#S41|bnPWnu>(`3Z>12yM~U
z(n>XlY7ysCgPa`PaHP2f3y~5;LVS%W3yJ|ImgV}3^R?1#&e-D;e5Eh0$AJsKC!OC0
zqm?Y?Q;tHk5Cl@-r10|?)l6R-+}t9iA3DHMlOeN=uwJ7V#hlADZjg?)6#@!Y(~R{Z
zt&jfspTU0i-y#PCOm!BU4zPvyW-SxTPM@V*t7CgP+C>afLtYBTt3NUY*s<_csX8w;
zhtmQeivcDWt^c4=iJ!I3(jOG})-vBHW5(wKYpnOK0PEOp_c<_EMGB}!p<m%jpqPn*
zy<@L*j#OK=2w5-HxT;}ynE7WD{JA5~F<O&5%Su?HK0oIL57R!e5V)vHP+SY0V`V^N
z`4CB|PER}h$<;ZOwmx{}+{hQqDnV<Q`@db{et#|$rho}S@xjEdQW@U56g~O!t1B!m
z%%F4Q|3h-S)yGP)mjx7F3Fm*PPkTTcOCt{H4pYE!v|dIiMKj6i<{E?mMn9t-2ZV(m
zrWwu75Hn1v3YghmCEvJ4U@}@)uX;g8<bd-*2Ez`fRHJg|J?v^n7(z`6dZ|Gf2X@p3
zy*X$o$<;yTGgLYE8TMIF3^Hx4cK0i@wX!QxTco*H*0;pCQt~N13dA4)IodWvN|Jxa
zM*&OK5*wWX{UrBwVXnA8UWsu6tixy3Zg;@WFvI4iKy#+5Fi(Gj*5%6xXD~i!gBbg~
zGDEq&LGDkEqwT2fxgR_FFEbxpC!74O3Srz>Ffh6HnH7iXm1aNvGW#qj2AQ@d<@MQm
z`RQh>bN``3OI+L7rMRb3i5NC}qbvXz`$6K>^;;uJa}17S^L6^g_;zo|X5sy55<J$9
z&KVfXk=YuxW|OT)zd}CfzrNz`_29kSQJHAaCauk(fP+Pc*%D<hfQST{1EX_*!Uujk
zIY0twVo=s%d&zHc0}E`g&we|0<ltv7yt?8A2$ZB&t)P7km}CIno3WQtpb)-bn#{0i
z20j~39-PB=J7^?CG0s^;nxY0h7<9RM`4U@eS19#+qm|t+0ARuxVKqryC1|dJ5R~8g
zAX{n9tp^*v#;kM_CT6tptB!;DO33<dkGgVPeDTuU4F$OJ;wARmp|gj6=h%^@Pn~<|
zVs!SNTe-Hj<5zL6QKi}GGv3WinHRy~z!(IOr8(=lAq05t3HmEnr{DY0ag}ub7-gOL
zm7W&B&%>Kff01XnLDSDW{P2%(jWWyi7@-8scH*}Y;J1L*(O3Y7%>)f)X<k|3?mLgy
zxPi&y0sHB>aQnc)g@2b120ZiBw^_ZmK@<j5%aK>uV+_{&2~)4l){Zb1?IiMnhgp8$
z0pe0T3U(}#bY}0kn+GM*s6rA~Fku-0s{&M>QaO5*BM-lu#e3gQ=j=PFhKimNgi^BE
z>S40nqsH6N7T19rbq9OlMH-Rf<Sj>53fNCjd~hS{t*-vYk)sDcx^i_b6f$6QeVdb~
zk7A8RFfq619SUIF6)eIDkPe6R*^n)trheuu3nfJ*PuRG4h1V{ufDq*61~%=FJB%c4
z%p==de)Z>O%9!{4m>=)7`h-YCtwej6(RYv*9)Y*nQkmWMz-L0E62WUP(@){HdycWT
z)B9s?V5;%1kJ1}v`ymVB)?zJQ*uJ**PU{anhF(8GDTy|QkqHn06X!rooIo(Gkt53t
z-F#F>WSW3=xQ!KzP~a?KXA6-H2xk|Wf5$sH_~3)|&fe#%|JHhonVBkCDWaEV%ol!R
zb%#95k>Cq)6etG641wcVWLSUtX%^o3Fnxkcxv{@mz<$J?zwsD1v(nb}S%-M#(z%NV
zv<%QHfC3Q&qn95Qpp^30N(D$I3)INV0wEDn_<)@(5dM14$8ktm2~4Mj>37Ms!IZ1G
znR#Rw;`2vJ-^)|$Xy<xQ&!sqI<=Xb>dT|DwYm!9!?sH_mg1T}Zd*W7h636j_Gamy!
z!wpQG_|Pv92I_{0nb~BaUVd%RYX5XL7y@7?EA1GWnBES;doh_JMjiyhQQ(-^<nT1q
zhEzr5<vOO?z{X|VIAdljB^1ycrX<?z)tK2*#O`+6|NEtd22nX;*iUJ-`;@|fV+Uv0
zjAq&CWh~8BzMSRemkYQNs{XFO<S%YUTl4ba#hFvB>#J{d)&k?6?f~4#@2d&pNBc*-
z2{!^aeeJw2#UYJyOeG45l%mxgl4Lnpw-<al49Ev5y@G?q%I7#LVd!hY+<YAwMO@z<
zkfs@pO8jaR$`1+{7H}if;(I@afbWV~U-{zViQ|8^eQot1xM>k^_z%yXjmI66N#0E!
zOyMZUp+9!d&(wU@8Dp`=Q7J|Ad&5cKo>CN`liVM^jx5g?J|zwUh6V=4(o1sEEXNs3
zG56It3O-<rTPxsZh?9Ts%X}}p{E7F<2Y&UpPo;_Y`t@(Wa!9KX9fTMeV3mRbSs=U*
zrs}|Gyj(4L0kk$qDG)*yh&}KC2xK6s)+!8#sXu1>Q7MSxh+(RID^^m_?ezWcsLV9j
zZ1!;0`M`y9)GFaO^Y->n0_%Ja69@k4@9^Dh^Iv>qa_kT9`y2o2tw~RPe(U1p`PW5I
z*aGJT2nr-}B8Yrlh`1b6u9i_jFlv2iMxKoW6oRM}5h#TNl3_{^Duk4y7p^EAz3mA|
z2C2UmQqWkOXKknJ=QwLAwvcPY?$g&k_sPGVp8MlIU;y_<zb_yF1w=r6+eiNHz2WRF
zzrA(t!r@V82r(+y6GEs7a#{c%j2A~pRG=tTO2p+7QjYEctaX!DZr|Qau9?_$agjkl
zX?}*y-JYKxg^GGfoinR1{+*S7^UGfahCntJz`hv*1V9LsfXd?AKX~%sLm&C)%~vnq
zo94y~pbM=04iYC7s8P^TPQ;kp`_?!TM2xPb5HQ&e2)vv4eNCoX1YTd7=i-G`s?`!D
zoe)Jq`@(O2{Qb6hZ42lF$yfmWy#!EvZxd4}3I=Nz^v-i%_|o#be!LdQ=q}Ui2{|cN
z;62Xb#-5S)IFG|w=dZoDetewD6K`<FdcsmnRI7Mjs+P%z36<6c>f$-vVBoq}U-*ap
z=O2B3D)4-I_1~xf6BAQjI-}Wn=FxA(%gg8LC+@tHZf{0tjTZttZgHakv7^A4Vqfsy
zdyEBZ{2Ubqs5n9=DW;%YQrPp~MqfIQvA}`leAvG7$*uqTkNzVt7z>aBdRl-tx&@}i
z3MRDxr~q}KAyl|<^uxdQ=agFbsdQtjp@qcwEuluWK`5M*9(>wM7<Yql>W{D4w+;M|
zpC4691W|-ZQ>-xrv3z0p;-mk#`PlD12XukK)ZU*6;NDCD0OV9Xh=KC75aI0dfdlXR
z%RjDYd??>(&KczEBFK>lR!E!}3BZ&9j1h>D5c^V2m14q~hL$8xWY?enPuu_HpMHHD
zcz+ytx^LgR@7K4+1fcc_Q5uU;r9hTyvrF&$`F90s{(a=!N4YAgH^{fQg-J536njF5
zF!EwpZAR_0R6@ovs$2po5@FLzg6vh@UVX0h<<CB$w=erbH=XkPR^9&Z`r4cvqkwQq
zj0h-=DaR-7UZ~&l!w-bVZo6HSN`XxVTG;RwXXP=c-IA<Ug$wehlhv0W$C|_rI=#Hp
z>LnMSTyd@I&2f-J@23NvE_NgA|B>$v?(Y!O*>MxE#>l<jACv?-(SV(-<k;t)@%6rE
zc8vSK>5G$M3V9R6l%F;?#(o#vg#S0bIeOz3D)x`>3&`yg<ojtqu>T2KHYP_G*Oz7h
O0000<MNUMnLSTaEL<B(q
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/dev-edition-promo/dev-edition-promo.css
@@ -0,0 +1,94 @@
+/* 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/. */
+
+window {
+  -moz-appearance: none;
+  background-color: transparent;
+}
+
+#doorhanger-container {
+  width: 450px;
+}
+
+#top-panel {
+  padding: 20px;
+  background: #343c45; /* toolbars */
+  color: #8fa1b2; /* body text */
+/*
+ * Sloppy preprocessing since UNIX_BUT_NOT_MAC is only defined
+ * in `browser/app/profile/firefox.js`, which this file cannot
+ * depend on. Must style font-size to target linux.
+ */
+%ifdef XP_UNIX
+%ifndef XP_MACOSX
+  font-size: 13px;
+%else
+  font-size: 15px;
+%endif
+%else
+  font-size: 15px;
+%endif
+  line-height: 19px;
+  min-height: 100px;
+}
+
+#top-panel h1 {
+  font-weight: bold;
+  font-family: Open Sans, sans-serif;
+  font-size: 1.1em;
+}
+
+#top-panel p {
+  font-family: Open Sans, sans-serif;
+  font-size: 0.9em;
+  width: 300px;
+  display: block;
+  margin: 5px 0px 0px 0px;
+}
+
+#icon {
+  background-image: url("chrome://browser/content/devtools/framework/dev-edition-logo.png");
+  background-size: 64px 64px;
+  background-repeat: no-repeat;
+  width: 64px;
+  height: 64px;
+  margin-right: 20px;
+}
+
+#lower-panel {
+  padding: 20px;
+  background-color: #252c33; /* tab toolbars */
+  min-height: 75px;
+  border-top: 1px solid #292e33; /* text high contrast (light) */
+}
+
+#button-container {
+  margin: auto 20px;
+}
+
+#button-container button {
+  font: message-box !important;
+  font-size: 16px !important;
+  cursor: pointer;
+  width: 125px;
+  opacity: 1;
+  position: static;
+  -moz-appearance: none;
+  border-radius: 5px;
+  height: 30px;
+  width: 450px;
+  /* Override embossed borders on Windows/Linux */
+  border: none;
+}
+
+#close {
+  background-color: transparent;
+  color: #8fa1b2; /* body text */
+}
+
+#go {
+  margin-left: 100px;
+  background-color: #70bf53; /* green */
+  color: #f5f7fa; /* selection text color */
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/dev-edition-promo/dev-edition-promo.xul
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+<!DOCTYPE window [
+<!ENTITY % toolboxDTD SYSTEM "chrome://browser/locale/devtools/toolbox.dtd" >
+ %toolboxDTD;
+]>
+<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
+<?xml-stylesheet rel="stylesheet" href="chrome://browser/content/devtools/framework/dev-edition-promo.css" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="dev-edition-promo">
+  <vbox id="doorhanger-container">
+    <hbox flex="1" id="top-panel">
+      <image id="icon" />
+      <vbox id="info">
+        <h1>Using Developer Tools in your browser?</h1>
+        <p>Download Firefox Developer Edition, our first browser made just for you.</p>
+      </vbox>
+    </hbox>
+    <hbox id="lower-panel" flex="1">
+      <hbox id="button-container" flex="1">
+        <button id="close"
+                flex="1"
+                standalone="true"
+                label="No thanks">
+        </button>
+        <button id="go"
+                flex="1"
+                standalone="true"
+                label="Learn more »">
+        </button>
+      </hbox>
+    </hbox>
+  </vbox>
+</window>
--- a/browser/devtools/framework/toolbox.js
+++ b/browser/devtools/framework/toolbox.js
@@ -12,16 +12,17 @@ const MIN_ZOOM = 0.5;
 const MAX_ZOOM = 2;
 
 let {Cc, Ci, Cu} = require("chrome");
 let {Promise: promise} = require("resource://gre/modules/Promise.jsm");
 let EventEmitter = require("devtools/toolkit/event-emitter");
 let Telemetry = require("devtools/shared/telemetry");
 let {getHighlighterUtils} = require("devtools/framework/toolbox-highlighter-utils");
 let HUDService = require("devtools/webconsole/hudservice");
+let {showDoorhanger} = require("devtools/shared/doorhanger");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
 Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 
@@ -94,16 +95,17 @@ function Toolbox(target, selectedTool, h
   this._splitConsoleOnKeypress = this._splitConsoleOnKeypress.bind(this);
   this.destroy = this.destroy.bind(this);
   this.highlighterUtils = getHighlighterUtils(this);
   this._highlighterReady = this._highlighterReady.bind(this);
   this._highlighterHidden = this._highlighterHidden.bind(this);
   this._prefChanged = this._prefChanged.bind(this);
   this._saveSplitConsoleHeight = this._saveSplitConsoleHeight.bind(this);
   this._onFocus = this._onFocus.bind(this);
+  this._showDevEditionPromo = this._showDevEditionPromo.bind(this);
 
   this._target.on("close", this.destroy);
 
   if (!hostType) {
     hostType = Services.prefs.getCharPref(this._prefs.LAST_HOST);
   }
   if (!selectedTool) {
     selectedTool = Services.prefs.getCharPref(this._prefs.LAST_TOOL);
@@ -118,16 +120,18 @@ function Toolbox(target, selectedTool, h
   EventEmitter.decorate(this);
 
   this._target.on("navigate", this._refreshHostTitle);
   this._target.on("frame-update", this._updateFrames);
 
   this.on("host-changed", this._refreshHostTitle);
   this.on("select", this._refreshHostTitle);
 
+  this.on("ready", this._showDevEditionPromo);
+
   gDevTools.on("tool-registered", this._toolRegistered);
   gDevTools.on("tool-unregistered", this._toolUnregistered);
 }
 exports.Toolbox = Toolbox;
 
 /**
  * The toolbox can be 'hosted' either embedded in a browser window
  * or in a separate window.
@@ -1555,10 +1559,23 @@ Toolbox.prototype = {
   },
 
   _highlighterReady: function() {
     this.emit("highlighter-ready");
   },
 
   _highlighterHidden: function() {
     this.emit("highlighter-hide");
+  },
+
+  /**
+   * For displaying the promotional Doorhanger on first opening of
+   * the developer tools, promoting the Developer Edition.
+   */
+  _showDevEditionPromo: function() {
+    // Do not display in browser toolbox
+    if (this.target.chrome) {
+      return;
+    }
+    let window = this.frame.contentWindow;
+    showDoorhanger({ window, type: "deveditionpromo" });
   }
 };
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -89,16 +89,19 @@ browser.jar:
     content/browser/devtools/commandline/commands-index.js             (commandline/commands-index.js)
     content/browser/devtools/framework/toolbox-window.xul              (framework/toolbox-window.xul)
     content/browser/devtools/framework/toolbox-options.xul             (framework/toolbox-options.xul)
     content/browser/devtools/framework/toolbox-options.js              (framework/toolbox-options.js)
     content/browser/devtools/framework/toolbox.xul                     (framework/toolbox.xul)
     content/browser/devtools/framework/options-panel.css               (framework/options-panel.css)
     content/browser/devtools/framework/toolbox-process-window.xul      (framework/toolbox-process-window.xul)
     content/browser/devtools/framework/toolbox-process-window.js       (framework/toolbox-process-window.js)
+    content/browser/devtools/framework/dev-edition-promo.xul           (framework/dev-edition-promo/dev-edition-promo.xul)
+*   content/browser/devtools/framework/dev-edition-promo.css           (framework/dev-edition-promo/dev-edition-promo.css)
+    content/browser/devtools/framework/dev-edition-logo.png            (framework/dev-edition-promo/dev-edition-logo.png)
     content/browser/devtools/inspector/inspector.xul                   (inspector/inspector.xul)
     content/browser/devtools/inspector/inspector.css                   (inspector/inspector.css)
     content/browser/devtools/connect.xhtml                             (framework/connect/connect.xhtml)
     content/browser/devtools/connect.css                               (framework/connect/connect.css)
     content/browser/devtools/connect.js                                (framework/connect/connect.js)
     content/browser/devtools/app-manager/template.js                   (app-manager/content/template.js)
     content/browser/devtools/app-manager/utils.js                      (app-manager/content/utils.js)
     content/browser/devtools/app-manager/connection-footer.js          (app-manager/content/connection-footer.js)
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -12,16 +12,17 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource:///modules/devtools/FloatingScrollbars.jsm");
 Cu.import("resource://gre/modules/devtools/event-emitter.js");
 XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
                                   "resource://gre/modules/SystemAppProxy.jsm");
 
 var require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 let Telemetry = require("devtools/shared/telemetry");
+let {showDoorhanger} = require("devtools/shared/doorhanger");
 let {TouchEventHandler} = require("devtools/touch-events");
 
 this.EXPORTED_SYMBOLS = ["ResponsiveUIManager"];
 
 const MIN_WIDTH = 50;
 const MIN_HEIGHT = 50;
 
 const MAX_WIDTH = 10000;
@@ -212,16 +213,23 @@ function ResponsiveUI(aWindow, aTab)
 
   if (this.browser.contentWindow.document &&
       this.browser.contentWindow.document.readyState == "complete") {
     this.onPageLoad();
   }
 
   // E10S: We should be using target here. See bug 1028234
   ResponsiveUIManager.emit("on", { tab: this.tab });
+
+  // Hook to display promotional Developer Edition doorhanger. Only displayed once.
+  showDoorhanger({
+    window: this.mainWindow,
+    type: "deveditionpromo",
+    anchor: this.chromeDoc.querySelector("#content")
+  });
 }
 
 ResponsiveUI.prototype = {
   _transitionsEnabled: true,
   get transitionsEnabled() this._transitionsEnabled,
   set transitionsEnabled(aValue) {
     this._transitionsEnabled = aValue;
     if (aValue && !this._resizing && this.stack.hasAttribute("responsivemode")) {
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shared/doorhanger.js
@@ -0,0 +1,160 @@
+/* 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/. */
+
+"use strict";
+
+const { Ci, Cc } = require("chrome");
+const { Services } = require("resource://gre/modules/Services.jsm");
+const { DOMHelpers } = require("resource:///modules/devtools/DOMHelpers.jsm");
+const { Task } = require("resource://gre/modules/Task.jsm");
+const { Promise } = require("resource://gre/modules/Promise.jsm");
+const { setTimeout } = require("sdk/timers");
+const { getMostRecentBrowserWindow } = require("sdk/window/utils");
+
+const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+const DEV_EDITION_PROMO_URL = "chrome://browser/content/devtools/framework/dev-edition-promo.xul";
+const DEV_EDITION_PROMO_ENABLED_PREF = "devtools.devedition.promo.enabled";
+const DEV_EDITION_PROMO_SHOWN_PREF = "devtools.devedition.promo.shown";
+const DEV_EDITION_PROMO_URL_PREF = "devtools.devedition.promo.url";
+const LOCALE = Cc["@mozilla.org/chrome/chrome-registry;1"]
+               .getService(Ci.nsIXULChromeRegistry)
+               .getSelectedLocale("global");
+
+/**
+ * Only show Dev Edition promo if it's enabled (beta channel),
+ * if it has not been shown before, and it's a locale build
+ * for `en-US`
+ */
+function shouldDevEditionPromoShow () {
+  return Services.prefs.getBoolPref(DEV_EDITION_PROMO_ENABLED_PREF) &&
+         !Services.prefs.getBoolPref(DEV_EDITION_PROMO_SHOWN_PREF) &&
+         LOCALE === "en-US";
+}
+
+let TYPES = {
+  // The Developer Edition promo doorhanger, called by
+  // opening the toolbox, browser console, WebIDE, or responsive design mode
+  // in Beta releases. Only displayed once per profile.
+  deveditionpromo: {
+    predicate: shouldDevEditionPromoShow,
+    success: () => Services.prefs.setBoolPref(DEV_EDITION_PROMO_SHOWN_PREF, true),
+    action: () => {
+      let url = Services.prefs.getCharPref(DEV_EDITION_PROMO_URL_PREF);
+      getGBrowser().selectedTab = getGBrowser().addTab(url);
+    },
+    url: DEV_EDITION_PROMO_URL
+  }
+};
+
+let panelAttrs = {
+  orient: "vertical",
+  hidden: "false",
+  consumeoutsideclicks: "true",
+  noautofocus: "true",
+  align: "start",
+  role: "alert"
+};
+
+/**
+ * Helper to call a doorhanger, defined in `TYPES`, with defined conditions,
+ * success handlers and loads its own XUL in a frame. Takes an object with
+ * several properties:
+ *
+ * @param {XULWindow} window
+ *        The window that should house the doorhanger.
+ * @param {String} type
+ *        The type of doorhanger to be displayed is, using the `TYPES` definition.
+ * @param {String} selector
+ *        The selector that the doorhanger should be appended to within `window`.
+ *        Defaults to a XUL Document's `window` element.
+ */
+exports.showDoorhanger = Task.async(function *({ window, type, anchor }) {
+  let { predicate, success, url, action } = TYPES[type];
+  // Abort if predicate fails
+  if (!predicate()) {
+    return;
+  }
+
+  // Call success function to set preferences/cleanup immediately,
+  // so if triggered multiple times, only happens once (Windows/Linux)
+  success();
+
+  // Wait 200ms to prevent flickering where the popup is displayed
+  // before the underlying window (Windows 7, 64bit)
+  yield wait(200);
+
+  let document = window.document;
+
+  let panel = document.createElementNS(XULNS, "panel");
+  let frame = document.createElementNS(XULNS, "iframe");
+  let parentEl = document.querySelector("window");
+
+  frame.setAttribute("src", url);
+  let close = () => parentEl.removeChild(panel);
+
+  setDoorhangerStyle(panel, frame);
+
+  panel.appendChild(frame);
+  parentEl.appendChild(panel);
+
+  yield onFrameLoad(frame);
+
+  panel.openPopup(anchor);
+
+  let closeBtn = frame.contentDocument.querySelector("#close");
+  if (closeBtn) {
+    closeBtn.addEventListener("click", close);
+  }
+
+  let goBtn = frame.contentDocument.querySelector("#go");
+  if (goBtn) {
+    goBtn.addEventListener("click", () => {
+      if (action) {
+        action();
+      }
+      close();
+    });
+  }
+});
+
+function setDoorhangerStyle (panel, frame) {
+  Object.keys(panelAttrs).forEach(prop => panel.setAttribute(prop, panelAttrs[prop]));
+  panel.style.margin = "20px";
+  panel.style.borderRadius = "5px";
+  panel.style.border = "none";
+  panel.style.MozAppearance = "none";
+  panel.style.backgroundColor = "transparent";
+
+  frame.style.borderRadius = "5px";
+  frame.setAttribute("flex", "1");
+  frame.setAttribute("width", "450");
+  frame.setAttribute("height", "179");
+}
+
+function onFrameLoad (frame) {
+  let { resolve, promise } = Promise.defer();
+
+  if (frame.contentWindow) {
+    let domHelper = new DOMHelpers(frame.contentWindow);
+    domHelper.onceDOMReady(resolve);
+  } else {
+    let callback = () => {
+      frame.removeEventListener("DOMContentLoaded", callback);
+      resolve();
+    }
+    frame.addEventListener("DOMContentLoaded", callback);
+  }
+
+  return promise;
+}
+
+function getGBrowser () {
+  return getMostRecentBrowserWindow().gBrowser;
+}
+
+function wait (n) {
+  let { resolve, promise } = Promise.defer();
+  setTimeout(resolve, n);
+  return promise;
+}
--- a/browser/devtools/shared/moz.build
+++ b/browser/devtools/shared/moz.build
@@ -28,16 +28,17 @@ EXTRA_JS_MODULES.devtools += [
     'widgets/VariablesView.jsm',
     'widgets/VariablesViewController.jsm',
     'widgets/ViewHelpers.jsm',
 ]
 
 EXTRA_JS_MODULES.devtools.shared += [
     'autocomplete-popup.js',
     'd3.js',
+    'doorhanger.js',
     'frame-script-utils.js',
     'inplace-editor.js',
     'observable-object.js',
     'telemetry.js',
     'theme-switching.js',
     'undo.js',
 ]
 
--- a/browser/devtools/webconsole/hudservice.js
+++ b/browser/devtools/webconsole/hudservice.js
@@ -14,16 +14,17 @@ let Heritage = require("sdk/core/heritag
 loader.lazyGetter(this, "Telemetry", () => require("devtools/shared/telemetry"));
 loader.lazyGetter(this, "WebConsoleFrame", () => require("devtools/webconsole/webconsole").WebConsoleFrame);
 loader.lazyImporter(this, "promise", "resource://gre/modules/Promise.jsm", "Promise");
 loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
 loader.lazyImporter(this, "devtools", "resource://gre/modules/devtools/Loader.jsm");
 loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
 loader.lazyImporter(this, "DebuggerServer", "resource://gre/modules/devtools/dbg-server.jsm");
 loader.lazyImporter(this, "DebuggerClient", "resource://gre/modules/devtools/dbg-client.jsm");
+loader.lazyGetter(this, "showDoorhanger", () => require("devtools/shared/doorhanger").showDoorhanger);
 
 const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
 let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
 
 const BROWSER_CONSOLE_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
 
 // The preference prefix for all of the Browser Console filters.
 const BROWSER_CONSOLE_FILTER_PREFS_PREFIX = "devtools.browserconsole.filter.";
@@ -699,25 +700,32 @@ BrowserConsole.prototype = Heritage.exte
     this.ui._filterPrefsPrefix = BROWSER_CONSOLE_FILTER_PREFS_PREFIX;
 
     let window = this.iframeWindow;
 
     // Make sure that the closing of the Browser Console window destroys this
     // instance.
     let onClose = () => {
       window.removeEventListener("unload", onClose);
+      window.removeEventListener("focus", onFocus);
       this.destroy();
     };
     window.addEventListener("unload", onClose);
 
     // Make sure Ctrl-W closes the Browser Console window.
     window.document.getElementById("cmd_close").removeAttribute("disabled");
 
     this._telemetry.toolOpened("browserconsole");
 
+    // Create an onFocus handler just to display the dev edition promo.
+    // This is to prevent race conditions in some environments.
+    // Hook to display promotional Developer Edition doorhanger. Only displayed once.
+    let onFocus = () => showDoorhanger({ window, type: "deveditionpromo" });
+    window.addEventListener("focus", onFocus);
+
     this._bc_init = this.$init();
     return this._bc_init;
   },
 
   $destroy: WebConsole.prototype.destroy,
 
   /**
    * Destroy the object.
--- a/browser/devtools/webide/content/webide.js
+++ b/browser/devtools/webide/content/webide.js
@@ -16,16 +16,17 @@ const {Services} = Cu.import("resource:/
 const {AppProjects} = require("devtools/app-manager/app-projects");
 const {Connection} = require("devtools/client/connection-manager");
 const {AppManager} = require("devtools/webide/app-manager");
 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 const ProjectEditor = require("projecteditor/projecteditor");
 const {Devices} = Cu.import("resource://gre/modules/devtools/Devices.jsm");
 const {GetAvailableAddons} = require("devtools/webide/addons");
 const {GetTemplatesJSON, GetAddonsJSON} = require("devtools/webide/remote-resources");
+const {showDoorhanger} = require("devtools/shared/doorhanger");
 
 const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/webide.properties");
 
 const HTML = "http://www.w3.org/1999/xhtml";
 const HELP_URL = "https://developer.mozilla.org/docs/Tools/WebIDE/Troubleshooting";
 
 // download template index early
 GetTemplatesJSON(true);
@@ -112,16 +113,21 @@ let UI = {
     // we need to validate the project regularly. Let's assume that
     // if a modification happened, it happened when the window was
     // not focused.
     if (AppManager.selectedProject &&
         AppManager.selectedProject.type != "mainProcess" &&
         AppManager.selectedProject.type != "runtimeApp") {
       AppManager.validateProject(AppManager.selectedProject);
     }
+
+    // Hook to display promotional Developer Edition doorhanger. Only displayed once.
+    // Hooked into the `onfocus` event because sometimes does not work
+    // when run at the end of `init`. ¯\(°_o)/¯
+    showDoorhanger({ window, type: "deveditionpromo", anchor: document.querySelector("#deck") });
   },
 
   appManagerUpdate: function(event, what, details) {
     // Got a message from app-manager.js
     switch (what) {
       case "runtimelist":
         this.updateRuntimeList();
         break;
--- a/configure.in
+++ b/configure.in
@@ -3813,17 +3813,17 @@ MOZ_ANDROID_APZ=
 MOZ_TOOLKIT_SEARCH=1
 MOZ_UI_LOCALE=en-US
 MOZ_UNIVERSALCHARDET=1
 MOZ_URL_CLASSIFIER=
 MOZ_XUL=1
 MOZ_ZIPWRITER=1
 NS_PRINTING=1
 MOZ_PDF_PRINTING=
-MOZ_NO_SMART_CARDS=
+MOZ_DISABLE_CRYPTOLEGACY=
 NSS_DISABLE_DBM=
 NECKO_COOKIES=1
 NECKO_PROTOCOLS_DEFAULT="about app data file ftp http res viewsource websocket wyciwyg device"
 if test -n "$MOZ_RTSP"; then
   NECKO_PROTOCOLS_DEFAULT="$NECKO_PROTOCOLS_DEFAULT rtsp"
 fi
 USE_ARM_KUSER=
 BUILD_CTYPES=1
@@ -6386,22 +6386,22 @@ MOZ_ARG_DISABLE_BOOL(parental-controls,
    MOZ_DISABLE_PARENTAL_CONTROLS=)
 if test -n "$MOZ_DISABLE_PARENTAL_CONTROLS"; then
     AC_DEFINE(MOZ_DISABLE_PARENTAL_CONTROLS)
 fi
 
 AC_SUBST(MOZ_DISABLE_PARENTAL_CONTROLS)
 
 dnl ========================================================
-dnl = Disable smartcard support
-dnl ========================================================
-if test -n "$MOZ_NO_SMART_CARDS"; then
-    AC_DEFINE(MOZ_NO_SMART_CARDS)
-fi
-AC_SUBST(MOZ_NO_SMART_CARDS)
+dnl = Disable DOMCrypto
+dnl ========================================================
+if test -n "$MOZ_DISABLE_CRYPTOLEGACY"; then
+    AC_DEFINE(MOZ_DISABLE_CRYPTOLEGACY)
+fi
+AC_SUBST(MOZ_DISABLE_CRYPTOLEGACY)
 
 dnl ========================================================
 dnl = Disable EV certificate verification
 dnl ========================================================
 if test -n "$MOZ_NO_EV_CERTS"; then
     AC_DEFINE(MOZ_NO_EV_CERTS)
 fi
 AC_SUBST(MOZ_NO_EV_CERTS)
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_CSP_evalscript_main_allowed_getCRMFRequest.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <title>CSP eval script tests</title>
+    <script type="application/javascript"
+             src="file_CSP_evalscript_main_allowed_getCRMFRequest.js"></script>
+  </head>
+  <body>
+
+    Foo.
+
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_CSP_evalscript_main_allowed_getCRMFRequest.html^headers^
@@ -0,0 +1,2 @@
+Cache-Control: no-cache
+Content-Security-Policy: default-src 'self' ; script-src 'self' 'unsafe-eval'
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_CSP_evalscript_main_allowed_getCRMFRequest.js
@@ -0,0 +1,42 @@
+// some javascript for the CSP eval() tests
+// all of these evals should succeed, as the document loading this script
+// has script-src 'self' 'unsafe-eval'
+
+function logResult(str, passed) {
+  var elt = document.createElement('div');
+  var color = passed ? "#cfc;" : "#fcc";
+  elt.setAttribute('style', 'background-color:' + color + '; width:100%; border:1px solid black; padding:3px; margin:4px;');
+  elt.innerHTML = str;
+  document.body.appendChild(elt);
+}
+
+// callback for when stuff is allowed by CSP
+var onevalexecuted = (function(window) {
+    return function(shouldrun, what, data) {
+      window.parent.scriptRan(shouldrun, what, data);
+      logResult((shouldrun ? "PASS: " : "FAIL: ") + what + " : " + data, shouldrun);
+    };})(window);
+
+// callback for when stuff is blocked
+var onevalblocked = (function(window) {
+    return function(shouldrun, what, data) {
+      window.parent.scriptBlocked(shouldrun, what, data);
+      logResult((shouldrun ? "FAIL: " : "PASS: ") + what + " : " + data, !shouldrun);
+    };})(window);
+
+
+// Defer until document is loaded so that we can write the pretty result boxes
+// out.
+addEventListener('load', function() {
+  // test that allows crypto.generateCRMFRequest eval to run
+  try {
+      var script =
+        'console.log("dynamic script passed to crypto.generateCRMFRequest should execute")';
+      crypto.generateCRMFRequest('CN=0', 0, 0, null, script, 384, null, 'rsa-dual-use');
+      onevalexecuted(true, "eval(script) inside crypto.generateCRMFRequest",
+                     "eval executed during crypto.generateCRMFRequest");
+  } catch (e) {
+    onevalblocked(true, "eval(script) inside crypto.generateCRMFRequest",
+                  "eval was blocked during crypto.generateCRMFRequest");
+  }
+}, false);
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_CSP_evalscript_main_getCRMFRequest.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <title>CSP eval script tests</title>
+    <script type="application/javascript"
+             src="file_CSP_evalscript_main_getCRMFRequest.js"></script>
+  </head>
+  <body>
+
+    Foo.
+
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_CSP_evalscript_main_getCRMFRequest.html^headers^
@@ -0,0 +1,2 @@
+Cache-Control: no-cache
+Content-Security-Policy: default-src 'self'
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_CSP_evalscript_main_getCRMFRequest.js
@@ -0,0 +1,48 @@
+// some javascript for the CSP eval() tests
+
+function logResult(str, passed) {
+  var elt = document.createElement('div');
+  var color = passed ? "#cfc;" : "#fcc";
+  elt.setAttribute('style', 'background-color:' + color + '; width:100%; border:1px solid black; padding:3px; margin:4px;');
+  elt.innerHTML = str;
+  document.body.appendChild(elt);
+}
+
+window._testResults = {};
+
+// callback for when stuff is allowed by CSP
+var onevalexecuted = (function(window) {
+    return function(shouldrun, what, data) {
+      window._testResults[what] = "ran";
+      window.parent.scriptRan(shouldrun, what, data);
+      logResult((shouldrun ? "PASS: " : "FAIL: ") + what + " : " + data, shouldrun);
+    };})(window);
+
+// callback for when stuff is blocked
+var onevalblocked = (function(window) {
+    return function(shouldrun, what, data) {
+      window._testResults[what] = "blocked";
+      window.parent.scriptBlocked(shouldrun, what, data);
+      logResult((shouldrun ? "FAIL: " : "PASS: ") + what + " : " + data, !shouldrun);
+    };})(window);
+
+
+// Defer until document is loaded so that we can write the pretty result boxes
+// out.
+addEventListener('load', function() {
+  // generateCRMFRequest test -- make sure we cannot eval the callback if CSP is in effect
+  try {
+    var script = 'console.log("dynamic script eval\'d in crypto.generateCRMFRequest should be disallowed")';
+    crypto.generateCRMFRequest('CN=0', 0, 0, null, script, 384, null, 'rsa-dual-use');
+    onevalexecuted(false, "crypto.generateCRMFRequest()",
+                   "crypto.generateCRMFRequest() should not run!");
+  } catch (e) {
+    onevalblocked(false, "eval(script) inside crypto.generateCRMFRequest",
+                  "eval was blocked during crypto.generateCRMFRequest");
+  }
+
+
+}, false);
+
+
+
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_CSP_evalscript_no_CSP_at_all.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <title>CSP eval script tests: no CSP specified</title>
+    <script type="application/javascript"
+             src="file_CSP_evalscript_no_CSP_at_all.js"></script>
+  </head>
+  <body>
+
+    Foo. See bug 824652
+
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_CSP_evalscript_no_CSP_at_all.html^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-cache
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_CSP_evalscript_no_CSP_at_all.js
@@ -0,0 +1,42 @@
+// some javascript for the CSP eval() tests
+// all of these evals should succeed, as the document loading this script
+// has script-src 'self' 'unsafe-eval'
+
+function logResult(str, passed) {
+  var elt = document.createElement('div');
+  var color = passed ? "#cfc;" : "#fcc";
+  elt.setAttribute('style', 'background-color:' + color + '; width:100%; border:1px solid black; padding:3px; margin:4px;');
+  elt.innerHTML = str;
+  document.body.appendChild(elt);
+}
+
+// callback for when stuff is allowed by CSP
+var onevalexecuted = (function(window) {
+    return function(shouldrun, what, data) {
+      window.parent.scriptRan(shouldrun, what, data);
+      logResult((shouldrun ? "PASS: " : "FAIL: ") + what + " : " + data, shouldrun);
+    };})(window);
+
+// callback for when stuff is blocked
+var onevalblocked = (function(window) {
+    return function(shouldrun, what, data) {
+      window.parent.scriptBlocked(shouldrun, what, data);
+      logResult((shouldrun ? "FAIL: " : "PASS: ") + what + " : " + data, !shouldrun);
+    };})(window);
+
+
+// Defer until document is loaded so that we can write the pretty result boxes
+// out.
+addEventListener('load', function() {
+  // test that allows crypto.generateCRMFRequest eval to run when there is no CSP at all in place
+  try {
+      var script =
+        'console.log("dynamic script passed to crypto.generateCRMFRequest should execute")';
+      crypto.generateCRMFRequest('CN=0', 0, 0, null, script, 384, null, 'rsa-dual-use');
+      onevalexecuted(true, "eval(script) inside crypto.generateCRMFRequest: no CSP at all",
+                     "eval executed during crypto.generateCRMFRequest where no CSP is set at all");
+  } catch (e) {
+    onevalblocked(true, "eval(script) inside crypto.generateCRMFRequest",
+                  "eval was blocked during crypto.generateCRMFRequest");
+  }
+}, false);
--- a/content/base/test/csp/mochitest.ini
+++ b/content/base/test/csp/mochitest.ini
@@ -15,20 +15,29 @@ support-files =
   file_CSP_bug885433_allows.html
   file_CSP_bug885433_allows.html^headers^
   file_CSP_bug885433_blocks.html
   file_CSP_bug885433_blocks.html^headers^
   file_CSP_bug888172.html
   file_CSP_bug888172.sjs
   file_CSP_evalscript_main.js
   file_CSP_evalscript_main_allowed.js
+  file_CSP_evalscript_main_allowed_getCRMFRequest.js
+  file_CSP_evalscript_main_getCRMFRequest.js
   file_CSP_evalscript_main.html
   file_CSP_evalscript_main.html^headers^
   file_CSP_evalscript_main_allowed.html
   file_CSP_evalscript_main_allowed.html^headers^
+  file_CSP_evalscript_main_allowed_getCRMFRequest.html
+  file_CSP_evalscript_main_allowed_getCRMFRequest.html^headers^
+  file_CSP_evalscript_main_getCRMFRequest.html
+  file_CSP_evalscript_main_getCRMFRequest.html^headers^
+  file_CSP_evalscript_no_CSP_at_all.html
+  file_CSP_evalscript_no_CSP_at_all.html^headers^
+  file_CSP_evalscript_no_CSP_at_all.js
   file_CSP_frameancestors_main.html
   file_CSP_frameancestors_main.js
   file_CSP_frameancestors.sjs
   file_CSP_inlinescript_main.html
   file_CSP_inlinescript_main.html^headers^
   file_CSP_inlinescript_main_allowed.html
   file_CSP_inlinescript_main_allowed.html^headers^
   file_CSP_inlinestyle_main.html
@@ -98,16 +107,18 @@ support-files =
 
 [test_connect-src.html]
 [test_CSP.html]
 [test_CSP_bug663567.html]
 [test_CSP_bug802872.html]
 [test_CSP_bug885433.html]
 [test_CSP_bug888172.html]
 [test_CSP_evalscript.html]
+[test_CSP_evalscript_getCRMFRequest.html]
+skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # no (deprecated) window.crypto support in multiprocess (bug 824652)
 [test_CSP_frameancestors.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' # Times out, not sure why (bug 1008445)
 [test_CSP_inlinescript.html]
 [test_CSP_inlinestyle.html]
 [test_bug836922_npolicies.html]
 [test_bug886164.html]
 [test_csp_redirects.html]
 [test_CSP_bug910139.html]
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/test_CSP_evalscript_getCRMFRequest.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Content Security Policy "no eval" in crypto.getCRMFRequest()</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<iframe style="width:100%;height:300px;" id='cspframe'></iframe>
+<iframe style="width:100%;height:300px;" id='cspframe2'></iframe>
+<iframe style="width:100%;height:300px;" id='cspframe3'></iframe>
+<script class="testbody" type="text/javascript">
+
+var path = "/tests/content/base/test/csp/";
+
+var evalScriptsThatRan = 0;
+var evalScriptsBlocked = 0;
+var evalScriptsTotal = 3;
+
+// called by scripts that run
+var scriptRan = function(shouldrun, testname, data) {
+  evalScriptsThatRan++;
+  ok(shouldrun, 'EVAL SCRIPT RAN: ' + testname + '(' + data + ')');
+  checkTestResults();
+}
+
+// called when a script is blocked
+var scriptBlocked = function(shouldrun, testname, data) {
+  evalScriptsBlocked++;
+  ok(!shouldrun, 'EVAL SCRIPT BLOCKED: ' + testname + '(' + data + ')');
+  checkTestResults();
+}
+
+// Check to see if all the tests have run
+var checkTestResults = function() {
+  // if any test is incomplete, keep waiting
+  if (evalScriptsTotal - evalScriptsBlocked - evalScriptsThatRan > 0)
+    return;
+
+  // ... otherwise, finish
+  SimpleTest.finish();
+}
+
+function loadElements() {
+  // save this for last so that our listeners are registered.
+  // ... this loads the testbed of good and bad requests.
+  document.getElementById('cspframe').src = 'file_CSP_evalscript_main_getCRMFRequest.html';
+  document.getElementById('cspframe2').src = 'file_CSP_evalscript_main_allowed_getCRMFRequest.html';
+  document.getElementById('cspframe3').src = 'file_CSP_evalscript_no_CSP_at_all.html';
+}
+
+//////////////////////////////////////////////////////////////////////
+// set up and go
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["dom.unsafe_legacy_crypto.enabled", true]]},
+                          loadElements);
+</script>
+</pre>
+</body>
+</html>
--- a/content/media/MediaCache.cpp
+++ b/content/media/MediaCache.cpp
@@ -1169,16 +1169,17 @@ MediaCache::Update()
 
       MediaCacheStream* stream = mStreams[i];
       if (stream->mClosed)
         continue;
 
       // Figure out where we should be reading from. It's the first
       // uncached byte after the current mStreamOffset.
       int64_t dataOffset = stream->GetCachedDataEndInternal(stream->mStreamOffset);
+      MOZ_ASSERT(dataOffset >= 0);
 
       // Compute where we'd actually seek to to read at readOffset
       int64_t desiredOffset = dataOffset;
       if (stream->mIsTransportSeekable) {
         if (desiredOffset > stream->mChannelOffset &&
             desiredOffset <= stream->mChannelOffset + SEEK_VS_READ_THRESHOLD) {
           // Assume it's more efficient to just keep reading up to the
           // desired position instead of trying to seek
@@ -1697,16 +1698,17 @@ MediaCacheStream::NotifyDataLength(int64
 void
 MediaCacheStream::NotifyDataStarted(int64_t aOffset)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
   NS_WARN_IF_FALSE(aOffset == mChannelOffset,
                    "Server is giving us unexpected offset");
+  MOZ_ASSERT(aOffset >= 0);
   mChannelOffset = aOffset;
   if (mStreamLength >= 0) {
     // If we started reading at a certain offset, then for sure
     // the stream is at least that long.
     mStreamLength = std::max(mStreamLength, mChannelOffset);
   }
 }
 
@@ -2121,33 +2123,38 @@ MediaCacheStream::Seek(int32_t aWhence, 
 {
   NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
 
   ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
   if (mClosed)
     return NS_ERROR_FAILURE;
 
   int64_t oldOffset = mStreamOffset;
+  int64_t newOffset = mStreamOffset;
   switch (aWhence) {
   case PR_SEEK_END:
     if (mStreamLength < 0)
       return NS_ERROR_FAILURE;
-    mStreamOffset = mStreamLength + aOffset;
+    newOffset = mStreamLength + aOffset;
     break;
   case PR_SEEK_CUR:
-    mStreamOffset += aOffset;
+    newOffset += aOffset;
     break;
   case PR_SEEK_SET:
-    mStreamOffset = aOffset;
+    newOffset = aOffset;
     break;
   default:
     NS_ERROR("Unknown whence");
     return NS_ERROR_FAILURE;
   }
 
+  if (newOffset < 0)
+    return NS_ERROR_FAILURE;
+  mStreamOffset = newOffset;
+
   CACHE_LOG(PR_LOG_DEBUG, ("Stream %p Seek to %lld", this, (long long)mStreamOffset));
   gMediaCache->NoteSeek(this, oldOffset);
 
   gMediaCache->QueueUpdate();
   return NS_OK;
 }
 
 int64_t
@@ -2179,21 +2186,20 @@ MediaCacheStream::Read(char* aBuffer, ui
     if (mStreamLength >= 0) {
       // Don't try to read beyond the end of the stream
       int64_t bytesRemaining = mStreamLength - mStreamOffset;
       if (bytesRemaining <= 0) {
         // Get out of here and return NS_OK
         break;
       }
       size = std::min(size, bytesRemaining);
-      // Clamp size until 64-bit file size issues (bug 500784) are fixed.
+      // Clamp size until 64-bit file size issues are fixed.
       size = std::min(size, int64_t(INT32_MAX));
     }
 
-    int32_t bytes;
     int32_t cacheBlock = streamBlock < mBlocks.Length() ? mBlocks[streamBlock] : -1;
     if (cacheBlock < 0) {
       // We don't have a complete cached block here.
 
       if (count > 0) {
         // Some data has been read, so return what we've got instead of
         // blocking or trying to find a stream with a partial block.
         break;
@@ -2211,17 +2217,20 @@ MediaCacheStream::Read(char* aBuffer, ui
           streamWithPartialBlock = stream;
           break;
         }
       }
       if (streamWithPartialBlock) {
         // We can just use the data in mPartialBlockBuffer. In fact we should
         // use it rather than waiting for the block to fill and land in
         // the cache.
-        bytes = std::min<int64_t>(size, streamWithPartialBlock->mChannelOffset - mStreamOffset);
+        int64_t bytes = std::min<int64_t>(size, streamWithPartialBlock->mChannelOffset - mStreamOffset);
+        // Clamp bytes until 64-bit file size issues are fixed.
+        bytes = std::min(bytes, int64_t(INT32_MAX));
+        NS_ABORT_IF_FALSE(bytes >= 0 && bytes <= aCount, "Bytes out of range.");
         memcpy(aBuffer,
           reinterpret_cast<char*>(streamWithPartialBlock->mPartialBlockBuffer.get()) + offsetInStreamBlock, bytes);
         if (mCurrentMode == MODE_METADATA) {
           streamWithPartialBlock->mMetadataInPartialBlockBuffer = true;
         }
         mStreamOffset += bytes;
         count = bytes;
         break;
@@ -2235,16 +2244,17 @@ MediaCacheStream::Read(char* aBuffer, ui
         return NS_ERROR_FAILURE;
       }
       continue;
     }
 
     gMediaCache->NoteBlockUsage(this, cacheBlock, mCurrentMode, TimeStamp::Now());
 
     int64_t offset = cacheBlock*BLOCK_SIZE + offsetInStreamBlock;
+    int32_t bytes;
     NS_ABORT_IF_FALSE(size >= 0 && size <= INT32_MAX, "Size out of range.");
     nsresult rv = gMediaCache->ReadCacheFile(offset, aBuffer + count, int32_t(size), &bytes);
     if (NS_FAILED(rv)) {
       if (count == 0)
         return rv;
       // If we did successfully read some data, may as well return it
       break;
     }
@@ -2271,19 +2281,17 @@ MediaCacheStream::ReadAt(int64_t aOffset
 
   ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
   nsresult rv = Seek(nsISeekableStream::NS_SEEK_SET, aOffset);
   if (NS_FAILED(rv)) return rv;
   return Read(aBuffer, aCount, aBytes);
 }
 
 nsresult
-MediaCacheStream::ReadFromCache(char* aBuffer,
-                                  int64_t aOffset,
-                                  int64_t aCount)
+MediaCacheStream::ReadFromCache(char* aBuffer, int64_t aOffset, int64_t aCount)
 {
   ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
   if (mClosed)
     return NS_ERROR_FAILURE;
 
   // Read one block (or part of a block) at a time
   uint32_t count = 0;
   int64_t streamOffset = aOffset;
@@ -2295,28 +2303,31 @@ MediaCacheStream::ReadFromCache(char* aB
 
     if (mStreamLength >= 0) {
       // Don't try to read beyond the end of the stream
       int64_t bytesRemaining = mStreamLength - streamOffset;
       if (bytesRemaining <= 0) {
         return NS_ERROR_FAILURE;
       }
       size = std::min(size, bytesRemaining);
-      // Clamp size until 64-bit file size issues (bug 500784) are fixed.
+      // Clamp size until 64-bit file size issues are fixed.
       size = std::min(size, int64_t(INT32_MAX));
     }
 
     int32_t bytes;
     uint32_t channelBlock = uint32_t(mChannelOffset/BLOCK_SIZE);
     int32_t cacheBlock = streamBlock < mBlocks.Length() ? mBlocks[streamBlock] : -1;
     if (channelBlock == streamBlock && streamOffset < mChannelOffset) {
       // We can just use the data in mPartialBlockBuffer. In fact we should
       // use it rather than waiting for the block to fill and land in
       // the cache.
-      bytes = std::min<int64_t>(size, mChannelOffset - streamOffset);
+      // Clamp bytes until 64-bit file size issues are fixed.
+      int64_t toCopy = std::min<int64_t>(size, mChannelOffset - streamOffset);
+      bytes = std::min(toCopy, int64_t(INT32_MAX));
+      NS_ABORT_IF_FALSE(bytes >= 0 && bytes <= toCopy, "Bytes out of range.");
       memcpy(aBuffer + count,
         reinterpret_cast<char*>(mPartialBlockBuffer.get()) + offsetInStreamBlock, bytes);
     } else {
       if (cacheBlock < 0) {
         // We expect all blocks to be cached! Fail!
         return NS_ERROR_FAILURE;
       }
       int64_t offset = cacheBlock*BLOCK_SIZE + offsetInStreamBlock;
--- a/dom/base/Crypto.cpp
+++ b/dom/base/Crypto.cpp
@@ -122,16 +122,92 @@ SubtleCrypto*
 Crypto::Subtle()
 {
   if(!mSubtle) {
     mSubtle = new SubtleCrypto(GetParentObject());
   }
   return mSubtle;
 }
 
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+// Stub out the legacy nsIDOMCrypto methods. The actual
+// implementations are in security/manager/ssl/src/nsCrypto.{cpp,h}
+
+NS_IMETHODIMP
+Crypto::GetEnableSmartCardEvents(bool *aEnableSmartCardEvents)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+Crypto::SetEnableSmartCardEvents(bool aEnableSmartCardEvents)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+bool
+Crypto::EnableSmartCardEvents()
+{
+  return false;
+}
+
+void
+Crypto::SetEnableSmartCardEvents(bool aEnable, ErrorResult& aRv)
+{
+  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+}
+
+void
+Crypto::GetVersion(nsString& aVersion)
+{
+}
+
+mozilla::dom::CRMFObject*
+Crypto::GenerateCRMFRequest(JSContext* aContext,
+                            const nsCString& aReqDN,
+                            const nsCString& aRegToken,
+                            const nsCString& aAuthenticator,
+                            const nsCString& aEaCert,
+                            const nsCString& aJsCallback,
+                            const Sequence<JS::Value>& aArgs,
+                            ErrorResult& aRv)
+{
+  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+  return nullptr;
+}
+
+void
+Crypto::ImportUserCertificates(const nsAString& aNickname,
+                               const nsAString& aCmmfResponse,
+                               bool aDoForcedBackup,
+                               nsAString& aReturn,
+                               ErrorResult& aRv)
+{
+  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+}
+
+void
+Crypto::SignText(JSContext* aContext,
+                 const nsAString& aStringToSign,
+                 const nsAString& aCaOption,
+                 const Sequence<nsCString>& aArgs,
+                 nsAString& aReturn)
+
+{
+  aReturn.AssignLiteral("error:internalError");
+}
+
+void
+Crypto::Logout(ErrorResult& aRv)
+{
+  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+}
+
+#endif
+
 /* static */ uint8_t*
 Crypto::GetRandomValues(uint32_t aLength)
 {
   nsCOMPtr<nsIRandomGenerator> randomGenerator;
   nsresult rv;
   randomGenerator = do_GetService("@mozilla.org/security/random-generator;1");
   NS_ENSURE_TRUE(randomGenerator, nullptr);
 
--- a/dom/base/Crypto.h
+++ b/dom/base/Crypto.h
@@ -1,15 +1,25 @@
 /* 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/. */
 #ifndef mozilla_dom_Crypto_h
 #define mozilla_dom_Crypto_h
 
+#ifdef MOZ_DISABLE_CRYPTOLEGACY
 #include "nsIDOMCrypto.h"
+#else
+#include "nsIDOMCryptoLegacy.h"
+namespace mozilla {
+namespace dom {
+class CRMFObject;
+}
+}
+#endif
+
 #include "mozilla/dom/SubtleCrypto.h"
 #include "nsPIDOMWindow.h"
 
 #include "nsWrapperCache.h"
 #include "mozilla/dom/TypedArray.h"
 #define NS_DOMCRYPTO_CID \
   {0x929d9320, 0x251e, 0x11d4, { 0x8a, 0x7c, 0x00, 0x60, 0x08, 0xc8, 0x44, 0xc3} }
 
@@ -36,16 +46,48 @@ public:
   void
   GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray,
 		  JS::MutableHandle<JSObject*> aRetval,
 		  ErrorResult& aRv);
 
   SubtleCrypto*
   Subtle();
 
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+  virtual bool EnableSmartCardEvents();
+  virtual void SetEnableSmartCardEvents(bool aEnable, ErrorResult& aRv);
+
+  virtual void GetVersion(nsString& aVersion);
+
+  virtual mozilla::dom::CRMFObject*
+  GenerateCRMFRequest(JSContext* aContext,
+                      const nsCString& aReqDN,
+                      const nsCString& aRegToken,
+                      const nsCString& aAuthenticator,
+                      const nsCString& aEaCert,
+                      const nsCString& aJsCallback,
+                      const Sequence<JS::Value>& aArgs,
+                      ErrorResult& aRv);
+
+  virtual void ImportUserCertificates(const nsAString& aNickname,
+                                      const nsAString& aCmmfResponse,
+                                      bool aDoForcedBackup,
+                                      nsAString& aReturn,
+                                      ErrorResult& aRv);
+
+  virtual void SignText(JSContext* aContext,
+                        const nsAString& aStringToSign,
+                        const nsAString& aCaOption,
+                        const Sequence<nsCString>& aArgs,
+                        nsAString& aReturn);
+
+  virtual void Logout(ErrorResult& aRv);
+
+#endif
+
   // WebIDL
 
   nsPIDOMWindow*
   GetParentObject() const
   {
     return mWindow;
   }
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -80,16 +80,19 @@
 #include "nsIWidgetListener.h"
 #include "nsIBaseWindow.h"
 #include "nsIDeviceSensors.h"
 #include "nsIContent.h"
 #include "nsIDocShell.h"
 #include "nsIDocCharset.h"
 #include "nsIDocument.h"
 #include "Crypto.h"
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+#include "nsIDOMCryptoLegacy.h"
+#endif
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMOfflineResourceList.h"
 #include "nsDOMString.h"
 #include "nsIEmbeddingSiteWindow.h"
 #include "nsThreadUtils.h"
 #include "nsILoadContext.h"
@@ -2363,16 +2366,24 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       mDoc &&
       mDoc->NodePrincipal() != aDocument->NodePrincipal()) {
     NS_ERROR("Attempted forced inner window reuse while changing principal");
     return NS_ERROR_UNEXPECTED;
   }
 
   nsCOMPtr<nsIDocument> oldDoc = mDoc;
 
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+  // clear smartcard events, our document has gone away.
+  if (mCrypto && XRE_GetProcessType() != GeckoProcessType_Content) {
+    nsresult rv = mCrypto->SetEnableSmartCardEvents(false);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+#endif
+
   AutoJSAPI jsapi;
   jsapi.Init();
   JSContext *cx = jsapi.cx();
 
   if (!mDoc) {
     // First document load.
 
     // Get our private root. If it is equal to us, then we need to
@@ -4449,17 +4460,30 @@ nsGlobalWindow::GetApplicationCache(nsID
 }
 
 nsIDOMCrypto*
 nsGlobalWindow::GetCrypto(ErrorResult& aError)
 {
   FORWARD_TO_INNER_OR_THROW(GetCrypto, (aError), aError, nullptr);
 
   if (!mCrypto) {
-    mCrypto = new Crypto();
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+    if (XRE_GetProcessType() != GeckoProcessType_Content) {
+      nsresult rv;
+      mCrypto = do_CreateInstance(NS_CRYPTO_CONTRACTID, &rv);
+      if (NS_FAILED(rv)) {
+        aError.Throw(rv);
+        return nullptr;
+      }
+    } else
+#endif
+    {
+      mCrypto = new Crypto();
+    }
+
     mCrypto->Init(this);
   }
   return mCrypto;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto)
 {
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -246,17 +246,24 @@ DOMInterfaces = {
     'implicitJSContext': [ 'buffer' ],
     'resultNotAddRefed': [ 'buffer' ],
 },
 
 'Coordinates': {
     'headerFile': 'nsGeoPosition.h'
 },
 
+'CRMFObject': {
+    'headerFile': 'nsCrypto.h',
+    'nativeOwnership': 'owned',
+    'wrapperCache': False,
+},
+
 'Crypto' : {
+    'implicitJSContext': [ 'generateCRMFRequest', 'signText' ],
     'headerFile': 'Crypto.h'
 },
 
 'CSS': {
     'concrete': False,
 },
 
 'CSS2Properties': {
--- a/dom/events/test/test_all_synthetic_events.html
+++ b/dom/events/test/test_all_synthetic_events.html
@@ -378,16 +378,20 @@ const kEventConstructors = {
                                                                                   aProps.clientX, aProps.clientY,
                                                                                   aProps.ctrlKey, aProps.altKey, aProps.shiftKey, aProps.metaKey,
                                                                                   aProps.button, aProps.relatedTarget,
                                                                                   aProps.allowedDirections, aProps.direction, aProps.delta || 0.0,
                                                                                   aProps.clickCount);
                                                          return e;
                                                        },
                                              },
+  SmartCardEvent:                            { create: function (aName, aProps) {
+                                                         return new SmartCardEvent(aName, aProps);
+                                                       },
+                                             },
   SpeechRecognitionEvent:                    { create: function (aName, aProps) {
                                                          return new SpeechRecognitionEvent(aName, aProps);
                                                        },
                                              },
   SpeechSynthesisEvent:                      { create: function (aName, aProps) {
                                                          return new SpeechSynthesisEvent(aName, aProps);
                                                        },
                                              },
--- a/dom/events/test/test_eventctors.html
+++ b/dom/events/test/test_eventctors.html
@@ -743,16 +743,39 @@ e = new PopupBlockedEvent("hello",
                           { requestingWindow: window,
                             popupWindowFeatures: "features",
                             popupWindowName: "name"
                           });
 is(e.requestingWindow, window);
 is(e.popupWindowFeatures, "features");
 is(e.popupWindowName, "name");
 
+
+// SmartCardEvent
+
+try {
+  e = new SmartCardEvent();
+} catch(exp) {
+  ex = true;
+}
+ok(ex, "SmartCardEvent: First parameter is required!");
+ex = false;
+
+e = new SmartCardEvent("hello");
+is(e.type, "hello", "SmartCardEvent: Wrong event type!");
+ok(!e.isTrusted, "SmartCardEvent: Event shouldn't be trusted!");
+ok(!e.bubbles, "SmartCardEvent: Event shouldn't bubble!");
+ok(!e.cancelable, "SmartCardEvent: Event shouldn't be cancelable!");
+is(e.tokenName, "");
+document.dispatchEvent(e);
+is(receivedEvent, e, "SmartCardEvent: Wrong event!");
+
+e = new SmartCardEvent("hello", { tokenName: "foo" });
+is(e.tokenName, "foo");
+
 // WheelEvent
 
 try {
   e = new WheelEvent();
 } catch(exp) {
   ex = true;
 }
 ok(ex, "WheelEvent: First parameter is required!");
--- a/dom/interfaces/base/moz.build
+++ b/dom/interfaces/base/moz.build
@@ -11,17 +11,16 @@ XPIDL_SOURCES += [
     'nsIContentPermissionPrompt.idl',
     'nsIContentPrefService.idl',
     'nsIContentPrefService2.idl',
     'nsIContentURIGrouper.idl',
     'nsIDOMChromeWindow.idl',
     'nsIDOMClientRect.idl',
     'nsIDOMClientRectList.idl',
     'nsIDOMConstructor.idl',
-    'nsIDOMCrypto.idl',
     'nsIDOMGlobalObjectConstructor.idl',
     'nsIDOMGlobalPropertyInitializer.idl',
     'nsIDOMHistory.idl',
     'nsIDOMJSWindow.idl',
     'nsIDOMLocation.idl',
     'nsIDOMModalContentWindow.idl',
     'nsIDOMNavigator.idl',
     'nsIDOMScreen.idl',
@@ -33,16 +32,25 @@ XPIDL_SOURCES += [
     'nsIIdleObserver.idl',
     'nsIQueryContentEventResult.idl',
     'nsIServiceWorkerManager.idl',
     'nsIStructuredCloneContainer.idl',
     'nsITabChild.idl',
     'nsITabParent.idl',
 ]
 
+if CONFIG['MOZ_DISABLE_CRYPTOLEGACY']:
+    XPIDL_SOURCES += [
+        'nsIDOMCrypto.idl',
+    ]
+else:
+    XPIDL_SOURCES += [
+        'nsIDOMCryptoLegacy.idl',
+    ]
+
 if CONFIG['MOZ_B2G']:
     XPIDL_SOURCES += [
         'nsIDOMWindowB2G.idl',
     ]
 
 if CONFIG['MOZ_WEBSPEECH']:
     XPIDL_SOURCES += [
         'nsISpeechSynthesisGetter.idl'
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/base/nsIDOMCryptoLegacy.idl
@@ -0,0 +1,15 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "domstubs.idl"
+
+interface nsIDOMWindow;
+
+[uuid(c25ecf08-3f46-4420-bee4-8505792fd63a)]
+interface nsIDOMCrypto : nsISupports
+{
+  [notxpcom] void init(in nsIDOMWindow window);
+  attribute boolean         enableSmartCardEvents;
+};
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/crypto/mochitest-legacy.ini
@@ -0,0 +1,2 @@
+[test_legacy.html]
+skip-if = e10s
--- a/dom/tests/mochitest/crypto/mochitest.ini
+++ b/dom/tests/mochitest/crypto/mochitest.ini
@@ -1,4 +1,5 @@
 [DEFAULT]
 skip-if = e10s
 
 [test_getRandomValues.html]
+[test_no_legacy.html]
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/crypto/test_legacy.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test presence of legacy window.crypto features when
+         MOZ_DISABLE_CRYPTOLEGACY is NOT set and dom.unsafe_legacy_crypto.enabled is true</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+function test_unsafe_legacy_crypto_enabled() {
+  ok("crypto" in window, "crypto in window");
+  ok("version" in window.crypto, "version in window.crypto");
+  ok("enableSmartCardEvents" in window.crypto,
+     "enableSmartCardEvents in window.crypto");
+  ok("generateCRMFRequest" in window.crypto,
+     "generateCRMFRequest in window.crypto");
+  ok("importUserCertificates" in window.crypto,
+     "importUserCertificates in window.crypto");
+  ok("signText" in window.crypto, "signText in window.crypto");
+
+  function jsCallback () {
+  }
+
+  try {
+    window.crypto.generateCRMFRequest(null, null, null, null, jsCallback.toString());
+    ok(false, "window.crypto.generateCRMFRequest failed, should throw error");
+  } catch (e) {
+    ok(e.toString().search(/Failure/) > -1,
+       "Expected error: ReqDN cannot be null");
+  }
+
+  try {
+    window.crypto.generateCRMFRequest(document.documentElement, null, null, null,
+                                      null);
+    ok(false, "window.crypto.generateCRMFRequest failed, should throw error");
+  } catch (e) {
+    ok(e.toString().search(/Failure/) > -1,
+       "Expected error: jsCallback cannot be null");
+  }
+
+  try {
+    window.crypto.generateCRMFRequest(document.documentElement, null, null, null,
+                                      jsCallback.toString(), 1024);
+    ok(false, "window.crypto.generateCRMFRequest failed, should throw error");
+  } catch (e) {
+    ok(e.toString().search(/TypeError/) > -1,
+       "Expected error: Not enough arguments");
+  }
+
+  SimpleTest.finish();
+}
+
+SpecialPowers.pushPrefEnv({"set": [["dom.unsafe_legacy_crypto.enabled", true]]},
+                          test_unsafe_legacy_crypto_enabled);
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body></html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/crypto/test_no_legacy.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test lack of legacy window.crypto features when
+         MOZ_DISABLE_CRYPTOLEGACY is set or dom.unsafe_legacy_crypto.enabled is false</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+function test_unsafe_legacy_crypto_disabled() {
+  ok("crypto" in window, "crypto in window");
+  ok(!("version" in window.crypto), "version not in window.crypto");
+  ok(!("enableSmartCardEvents" in window.crypto),
+     "enableSmartCardEvents not in window.crypto");
+  ok(!("generateCRMFRequest" in window.crypto),
+     "generateCRMFRequest not in window.crypto");
+  ok(!("importUserCertificates" in window.crypto),
+     "importUserCertificates not in window.crypto");
+  ok(!("signText" in window.crypto), "signText not in window.crypto");
+
+  SimpleTest.finish();
+}
+
+SpecialPowers.pushPrefEnv({"set": [["dom.unsafe_legacy_crypto.enabled", false]]},
+                          test_unsafe_legacy_crypto_disabled);
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body></html>
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -859,16 +859,18 @@ var interfaceNamesInGlobalScope =
     {name: "ShadowRoot", pref: "dom.webcomponents.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "SharedWorker", pref: "dom.workers.sharedWorkers.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "SimpleGestureEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "SimpleTest", xbl: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    "SmartCardEvent",
+// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "SpeechSynthesisEvent", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "SpeechSynthesis", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "SpeechSynthesisUtterance", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "SpeechSynthesisVoice", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/tests/moz.build
+++ b/dom/tests/moz.build
@@ -43,15 +43,20 @@ MOCHITEST_CHROME_MANIFESTS += [
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gtk2':
     # Bug 788164.
     MOCHITEST_MANIFESTS += [
         'mochitest/pointerlock/mochitest.ini',
     ]
 
+if not CONFIG['MOZ_DISABLE_CRYPTOLEGACY']:
+    MOCHITEST_MANIFESTS += [
+        'mochitest/crypto/mochitest-legacy.ini',
+    ]
+
 if CONFIG['MOZ_GAMEPAD']:
     MOCHITEST_MANIFESTS += [
         'mochitest/gamepad/mochitest.ini',
     ]
 
 XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
 BROWSER_CHROME_MANIFESTS += ['browser/browser.ini']
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CRMFObject.webidl
@@ -0,0 +1,10 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ */
+
+[NoInterfaceObject]
+interface CRMFObject {
+  readonly attribute DOMString request;
+};
--- a/dom/webidl/Crypto.webidl
+++ b/dom/webidl/Crypto.webidl
@@ -14,8 +14,43 @@ interface RandomSource {
 };
 
 Crypto implements RandomSource;
 
 interface Crypto {
   [Pref="dom.webcrypto.enabled"]
   readonly attribute SubtleCrypto subtle;
 };
+
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+[NoInterfaceObject]
+interface CryptoLegacy {
+  [Pref="dom.unsafe_legacy_crypto.enabled"]
+  readonly attribute DOMString version;
+
+  [SetterThrows,Pref="dom.unsafe_legacy_crypto.enabled"]
+  attribute boolean enableSmartCardEvents;
+
+  [Throws,NewObject,Pref="dom.unsafe_legacy_crypto.enabled"]
+  CRMFObject? generateCRMFRequest(ByteString? reqDN,
+                                  ByteString? regToken,
+                                  ByteString? authenticator,
+                                  ByteString? eaCert,
+                                  ByteString? jsCallback,
+                                  any... args);
+
+  [Throws,Pref="dom.unsafe_legacy_crypto.enabled"]
+  DOMString importUserCertificates(DOMString nickname,
+                                   DOMString cmmfResponse,
+                                   boolean doForcedBackup);
+
+  [Pref="dom.unsafe_legacy_crypto.enabled"]
+  DOMString signText(DOMString stringToSign,
+                     DOMString caOption,
+                     ByteString... args);
+
+  [Throws,Pref="dom.unsafe_legacy_crypto.enabled"]
+  void logout();
+};
+
+Crypto implements CryptoLegacy;
+#endif // !MOZ_DISABLE_CRYPTOLEGACY
+
new file mode 100644
--- /dev/null
+++ b/dom/webidl/SmartCardEvent.webidl
@@ -0,0 +1,16 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ */
+
+[Constructor(DOMString type, optional SmartCardEventInit eventInitDict)]
+interface SmartCardEvent : Event
+{
+  readonly attribute DOMString? tokenName;
+};
+
+dictionary SmartCardEventInit : EventInit
+{
+  DOMString tokenName = "";
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -558,16 +558,17 @@ WEBIDL_FILES += [
     'HashChangeEvent.webidl',
     'MozApplicationEvent.webidl',
     'MozSettingsEvent.webidl',
     'PageTransitionEvent.webidl',
     'PopStateEvent.webidl',
     'PopupBlockedEvent.webidl',
     'ProgressEvent.webidl',
     'RecordErrorEvent.webidl',
+    'SmartCardEvent.webidl',
     'StyleRuleChangeEvent.webidl',
     'StyleSheetApplicableStateChangeEvent.webidl',
     'StyleSheetChangeEvent.webidl',
 ]
 
 # We only expose our prefable test interfaces in debug builds, just to be on
 # the safe side.
 if CONFIG['MOZ_DEBUG']:
@@ -632,16 +633,21 @@ else:
         'InstallTrigger.webidl',
     ]
 
 if CONFIG['MOZ_B2G_FM']:
     WEBIDL_FILES += [
         'FMRadio.webidl',
     ]
 
+if not CONFIG['MOZ_DISABLE_CRYPTOLEGACY']:
+    WEBIDL_FILES += [
+        'CRMFObject.webidl',
+    ]
+
 GENERATED_EVENTS_WEBIDL_FILES = [
     'AutocompleteErrorEvent.webidl',
     'BlobEvent.webidl',
     'CallEvent.webidl',
     'CallGroupErrorEvent.webidl',
     'CFStateChangeEvent.webidl',
     'CloseEvent.webidl',
     'DataErrorEvent.webidl',
@@ -674,16 +680,17 @@ GENERATED_EVENTS_WEBIDL_FILES = [
     'PopupBlockedEvent.webidl',
     'ProgressEvent.webidl',
     'RecordErrorEvent.webidl',
     'RTCDataChannelEvent.webidl',
     'RTCPeerConnectionIceEvent.webidl',
     'RTCPeerConnectionIdentityErrorEvent.webidl',
     'RTCPeerConnectionIdentityEvent.webidl',
     'SelectionChangeEvent.webidl',
+    'SmartCardEvent.webidl',
     'StyleRuleChangeEvent.webidl',
     'StyleSheetApplicableStateChangeEvent.webidl',
     'StyleSheetChangeEvent.webidl',
     'TrackEvent.webidl',
     'UDPMessageEvent.webidl',
     'UserProximityEvent.webidl',
     'USSDReceivedEvent.webidl',
 ]
--- a/gfx/layers/Compositor.cpp
+++ b/gfx/layers/Compositor.cpp
@@ -99,32 +99,16 @@ Compositor::DrawDiagnostics(DiagnosticFl
   if (!ShouldDrawDiagnostics(aFlags)) {
     return;
   }
 
   DrawDiagnosticsInternal(aFlags, aVisibleRect, aClipRect, aTransform,
                           aFlashCounter);
 }
 
-RenderTargetRect
-Compositor::ClipRectInLayersCoordinates(Layer* aLayer, RenderTargetIntRect aClip) const {
-  ContainerLayer* parent = aLayer->AsContainerLayer() ? aLayer->AsContainerLayer() : aLayer->GetParent();
-  while (!parent->UseIntermediateSurface() && parent->GetParent()) {
-    parent = parent->GetParent();
-  }
-
-  RenderTargetIntPoint renderTargetOffset = RenderTargetIntRect::FromUntyped(
-    parent->GetEffectiveVisibleRegion().GetBounds()).TopLeft();
-
-  RenderTargetRect result;
-  aClip = aClip + renderTargetOffset;
-  result = RenderTargetRect(aClip.x, aClip.y, aClip.width, aClip.height);
-  return result;
-}
-
 void
 Compositor::DrawDiagnosticsInternal(DiagnosticFlags aFlags,
                                     const gfx::Rect& aVisibleRect,
                                     const gfx::Rect& aClipRect,
                                     const gfx::Matrix4x4& aTransform,
                                     uint32_t aFlashCounter)
 {
 #ifdef MOZ_B2G
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -488,25 +488,16 @@ public:
   ScreenRotation GetScreenRotation() const {
     return mScreenRotation;
   }
 
   void SetScreenRotation(ScreenRotation aRotation) {
     mScreenRotation = aRotation;
   }
 
-  // On b2g the clip rect is in the coordinate space of the physical screen
-  // independently of its rotation, while the coordinate space of the layers,
-  // on the other hand, depends on the screen orientation.
-  // This only applies to b2g as with other platforms, orientation is handled
-  // at the OS level rather than in Gecko.
-  // In addition, the clip rect needs to be offset by the rendering origin.
-  // This becomes important if intermediate surfaces are used.
-  RenderTargetRect ClipRectInLayersCoordinates(Layer* aLayer, RenderTargetIntRect aClip) const;
-
 protected:
   void DrawDiagnosticsInternal(DiagnosticFlags aFlags,
                                const gfx::Rect& aVisibleRect,
                                const gfx::Rect& aClipRect,
                                const gfx::Matrix4x4& transform,
                                uint32_t aFlashCounter);
 
   bool ShouldDrawDiagnostics(DiagnosticFlags);
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -196,28 +196,16 @@ ContainerPrepare(ContainerT* aContainer,
 
     RenderTargetIntRect clipRect = layerToRender->GetLayer()->
         CalculateScissorRect(aClipRect);
     if (clipRect.IsEmpty()) {
       CULLING_LOG("Sublayer %p has an empty world clip rect\n", layerToRender->GetLayer());
       continue;
     }
 
-    RenderTargetRect quad = layerToRender->GetLayer()->
-      TransformRectToRenderTarget(LayerPixel::FromUntyped(
-        layerToRender->GetLayer()->GetEffectiveVisibleRegion().GetBounds()));
-
-    Compositor* compositor = aManager->GetCompositor();
-    if (!layerToRender->GetLayer()->AsContainerLayer() &&
-        !quad.Intersects(compositor->ClipRectInLayersCoordinates(layerToRender->GetLayer(), clipRect)) &&
-        !LayerHasCheckerboardingAPZC(layerToRender->GetLayer(), nullptr)) {
-      CULLING_LOG("Sublayer %p is clipped entirely\n", layerToRender->GetLayer());
-      continue;
-    }
-
     CULLING_LOG("Preparing sublayer %p\n", layerToRender->GetLayer());
 
     nsIntRegion savedVisibleRegion;
     bool restoreVisibleRegion = false;
     gfx::Matrix matrix;
     bool is2D = layerToRender->GetLayer()->GetBaseTransform().Is2D(&matrix);
     if (i + 1 < children.Length() &&
         is2D && !matrix.HasNonIntegerTranslation()) {
@@ -396,16 +384,17 @@ RenderIntermediate(ContainerT* aContaine
                    RefPtr<CompositingRenderTarget> surface)
 {
   Compositor* compositor = aManager->GetCompositor();
   RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();
 
   if (!surface) {
     return;
   }
+
   compositor->SetRenderTarget(surface);
   // pre-render all of the layers into our temporary
   RenderLayers(aContainer, aManager, RenderTargetPixel::FromUntyped(aClipRect));
   // Unbind the current surface and rebind the previous one.
   compositor->SetRenderTarget(previousTarget);
 }
 
 template<class ContainerT> void
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -456,25 +456,16 @@ TiledContentHost::RenderTile(const TileH
                              const nsIntSize& aTextureBounds)
 {
   if (aTile.IsPlaceholderTile()) {
     // This shouldn't ever happen, but let's fail semi-gracefully. No need
     // to warn, the texture update would have already caught this.
     return;
   }
 
-  nsIntRect screenBounds = aScreenRegion.GetBounds();
-  Rect layerQuad(screenBounds.x, screenBounds.y, screenBounds.width, screenBounds.height);
-  RenderTargetRect quad = RenderTargetRect::FromUnknown(aTransform.TransformBounds(layerQuad));
-
-  if (!quad.Intersects(mCompositor->ClipRectInLayersCoordinates(mLayer,
-      RenderTargetIntRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height)))) {
-    return;
-  }
-
   if (aBackgroundColor) {
     aEffectChain.mPrimaryEffect = new EffectSolidColor(ToColor(*aBackgroundColor));
     nsIntRegionRectIterator it(aScreenRegion);
     for (const nsIntRect* rect = it.Next(); rect != nullptr; rect = it.Next()) {
       Rect graphicsRect(rect->x, rect->y, rect->width, rect->height);
       mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, 1.0, aTransform);
     }
   }
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -1523,17 +1523,17 @@ bool DoesD3D11DeviceWork(ID3D11Device *d
     gfxWindowsPlatform::GetDLLVersion(L"dlumd32.dll", displayLinkModuleVersionString);
     uint64_t displayLinkModuleVersion;
     if (!ParseDriverVersion(displayLinkModuleVersionString, &displayLinkModuleVersion)) {
 #if defined(MOZ_CRASHREPORTER)
       CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DisplayLink: could not parse version\n"));
 #endif
       return false;
     }
-    if (displayLinkModuleVersion <= GFX_DRIVER_VERSION(8,6,1,36484)) {
+    if (displayLinkModuleVersion <= V(8,6,1,36484)) {
 #if defined(MOZ_CRASHREPORTER)
       CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DisplayLink: too old version\n"));
 #endif
       return false;
     }
   }
 
   if (GetModuleHandleW(L"atidxx32.dll")) {
--- a/media/libnestegg/include/nestegg-stdint.h
+++ b/media/libnestegg/include/nestegg-stdint.h
@@ -1,7 +1,10 @@
 #ifdef _WIN32
 typedef __int64 int64_t;
 typedef unsigned __int64 uint64_t;
+#if !defined(INT64_MAX)
+#define INT64_MAX 9223372036854775807LL
+#endif
 #else
 #include <stdint.h>
 #endif
 
--- a/media/libnestegg/src/nestegg.c
+++ b/media/libnestegg/src/nestegg.c
@@ -1945,16 +1945,19 @@ nestegg_get_cue_point(nestegg * ctx, uns
   return 0;
 }
 
 int
 nestegg_offset_seek(nestegg * ctx, uint64_t offset)
 {
   int r;
 
+  if (offset > INT64_MAX)
+    return -1;
+
   /* Seek and set up parser state for segment-level element (Cluster). */
   r = ne_io_seek(ctx->io, offset, NESTEGG_SEEK_SET);
   if (r != 0)
     return -1;
   ctx->last_valid = 0;
 
   while (ctx->ancestor)
     ne_ctx_pop(ctx);
--- a/mobile/android/confvars.sh
+++ b/mobile/android/confvars.sh
@@ -13,17 +13,17 @@ MOZ_OFFICIAL_BRANDING_DIRECTORY=mobile/a
 # MOZ_APP_DISPLAYNAME is set by branding/configure.sh
 
 # We support Android SDK version 9 and up by default.
 # See the --enable-android-min-sdk and --enable-android-max-sdk arguments in configure.in.
 MOZ_ANDROID_MIN_SDK_VERSION=9
 
 MOZ_SAFE_BROWSING=1
 
-MOZ_NO_SMART_CARDS=1
+MOZ_DISABLE_CRYPTOLEGACY=1
 
 # Enable getUserMedia
 MOZ_MEDIA_NAVIGATOR=1
 
 # Enable NFC permission
 MOZ_ANDROID_BEAM=1
 
 if test "$LIBXUL_SDK"; then
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4290,8 +4290,10 @@ pref("dom.fetch.enabled", false);
 // it is running on a low memory platform, features that can be reliably
 // supported will be disabled. This threshold can be adjusted to suit other
 // platforms; and set to 0 to disable the low-memory check altogether.
 pref("camera.control.low_memory_thresholdMB", 404);
 #endif
 
 // UDPSocket API
 pref("dom.udpsocket.enabled", false);
+
+pref("dom.unsafe_legacy_crypto.enabled", true);
--- a/security/certverifier/CertVerifier.cpp
+++ b/security/certverifier/CertVerifier.cpp
@@ -367,17 +367,18 @@ CertVerifier::VerifyCert(CERTCertificate
                           KeyPurposeId::id_kp_codeSigning,
                           CertPolicyId::anyPolicy, stapledOCSPResponse);
       break;
     }
 
     case certificateUsageVerifyCA:
     case certificateUsageStatusResponder: {
       // XXX This is a pretty useless way to verify a certificate. It is used
-      // by the certificate viewer UI. Because we don't know what trust bit is
+      // by the implementation of window.crypto.importCertificates and in the
+      // certificate viewer UI. Because we don't know what trust bit is
       // interesting, we just try them all.
       mozilla::pkix::EndEntityOrCA endEntityOrCA;
       mozilla::pkix::KeyUsage keyUsage;
       KeyPurposeId eku;
       if (usage == certificateUsageVerifyCA) {
         endEntityOrCA = EndEntityOrCA::MustBeCA;
         keyUsage = KeyUsage::keyCertSign;
         eku = KeyPurposeId::anyExtendedKeyUsage;
--- a/security/manager/pki/resources/content/certManager.js
+++ b/security/manager/pki/resources/content/certManager.js
@@ -27,32 +27,21 @@ var selected_index = [];
 var certdb;
 
 var caTreeView;
 var serverTreeView;
 var emailTreeView;
 var userTreeView;
 var orphanTreeView;
 
-var smartCardObserver = {
-  observe: function() {
-    onSmartCardChange();
-  }
-};
-
-function DeregisterSmartCardObservers()
-{
-  Services.obs.removeObserver(smartCardObserver, "smartcard-insert");
-  Services.obs.removeObserver(smartCardObserver, "smartcard-remove");
-}
-
 function LoadCerts()
 {
-  Services.obs.addObserver(smartCardObserver, "smartcard-insert", false);
-  Services.obs.addObserver(smartCardObserver, "smartcard-remove", false);
+  window.crypto.enableSmartCardEvents = true;
+  document.addEventListener("smartcard-insert", onSmartCardChange, false);
+  document.addEventListener("smartcard-remove", onSmartCardChange, false);
 
   certdb = Components.classes[nsX509CertDB].getService(nsIX509CertDB);
   var certcache = Components.classes[nsNSSCertCache].createInstance(nsINSSCertCache);
   
   certcache.cacheAllCerts();
 
   caTreeView = Components.classes[nsCertTree]
                     .createInstance(nsICertTree);
@@ -619,8 +608,9 @@ function addException()
                     'chrome,centerscreen,modal');
   var certcache = Components.classes[nsNSSCertCache].createInstance(nsINSSCertCache);
   certcache.cacheAllCerts();
   serverTreeView.loadCertsFromCache(certcache, nsIX509Cert.SERVER_CERT);
   serverTreeView.selection.clearSelection();
   orphanTreeView.loadCertsFromCache(certcache, nsIX509Cert.UNKNOWN_CERT);
   orphanTreeView.selection.clearSelection();
 }
+
--- a/security/manager/pki/resources/content/certManager.xul
+++ b/security/manager/pki/resources/content/certManager.xul
@@ -13,17 +13,16 @@
 
 <!DOCTYPE dialog SYSTEM "chrome://pippki/locale/certManager.dtd">
 
 <dialog id="certmanager" 
 	windowtype="mozilla:certmanager"
 	xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 
         title="&certmgr.title;"
         onload="LoadCerts();"
-        onunload="DeregisterSmartCardObservers();"
         buttons="accept"
         style="width: 48em; height: 32em;"
         persist="screenX screenY width height">
 
   <stringbundle id="pippki_bundle" src="chrome://pippki/locale/pippki.properties"/>
 
   <script type="application/javascript" src="chrome://pippki/content/pippki.js"/>
   <script type="application/javascript" src="chrome://pippki/content/certManager.js"/>
--- a/security/manager/pki/resources/content/device_manager.js
+++ b/security/manager/pki/resources/content/device_manager.js
@@ -11,41 +11,28 @@ const nsIPKCS11ModuleDB = Components.int
 const nsIPK11Token = Components.interfaces.nsIPK11Token;
 const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1";
 const nsIPK11TokenDB = Components.interfaces.nsIPK11TokenDB;
 const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock;
 const nsDialogParamBlock = "@mozilla.org/embedcomp/dialogparam;1";
 const nsIPKCS11 = Components.interfaces.nsIPKCS11;
 const nsPKCS11ContractID = "@mozilla.org/security/pkcs11;1";
 
-let { Services } = Components.utils.import("resource://gre/modules/Services.jsm", {});
-
 var bundle;
 var secmoddb;
 var skip_enable_buttons = false;
 
-var smartCardObserver = {
-  observe: function() {
-    onSmartCardChange();
-  }
-};
-
-function DeregisterSmartCardObservers()
-{
-  Services.obs.removeObserver(smartCardObserver, "smartcard-insert");
-  Services.obs.removeObserver(smartCardObserver, "smartcard-remove");
-}
-
 /* Do the initial load of all PKCS# modules and list them. */
 function LoadModules()
 {
   bundle = document.getElementById("pippki_bundle");
   secmoddb = Components.classes[nsPKCS11ModuleDB].getService(nsIPKCS11ModuleDB);
-  Services.obs.addObserver(smartCardObserver, "smartcard-insert", false);
-  Services.obs.addObserver(smartCardObserver, "smartcard-remove", false);
+  window.crypto.enableSmartCardEvents = true;
+  document.addEventListener("smartcard-insert", onSmartCardChange, false);
+  document.addEventListener("smartcard-remove", onSmartCardChange, false);
 
   RefreshDeviceList();
 }
 
 function getPKCS11()
 {
   return Components.classes[nsPKCS11ContractID].getService(nsIPKCS11);
 }
--- a/security/manager/pki/resources/content/device_manager.xul
+++ b/security/manager/pki/resources/content/device_manager.xul
@@ -14,17 +14,16 @@
 
 <dialog id="devicemanager"
 	windowtype="mozilla:devicemanager"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 
         title="&devmgr.title;"
         style="&devmgr.style;"
         persist="screenX screenY width height"
         onload="LoadModules();"
-        onunload="DeregisterSmartCardObservers();"
         buttons="accept">
 
 <stringbundleset id="stringbundleset">
   <stringbundle id="pippki_bundle" src="chrome://pippki/locale/pippki.properties"/>
   <stringbundle id="pipnss_bundle" src="chrome://pipnss/locale/pipnss.properties"/>
 </stringbundleset>
 
 <script type="application/javascript" src="chrome://pippki/content/device_manager.js"/>
new file mode 100644
--- /dev/null
+++ b/security/manager/pki/resources/content/formsigning.js
@@ -0,0 +1,67 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* 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/. */
+
+const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock;
+
+var dialogParams;
+var itemCount = 0;
+
+function onLoad()
+{
+  dialogParams = window.arguments[0].QueryInterface(nsIDialogParamBlock);
+
+  var hostname = dialogParams.GetString(0);
+  var bundle = document.getElementById("pippki_bundle");
+  var intro = "The site '" + hostname + "' has requested that you sign the following text message:";
+  setText("sign.intro", intro);
+
+  document.getElementById("sign.text").value = dialogParams.GetString(1);
+
+  var selectElement = document.getElementById("nicknames");
+  itemCount = dialogParams.GetInt(0);
+  for (var index = 0; index < itemCount; ++index) {
+    var menuItemNode = document.createElement("menuitem");
+    var nick = dialogParams.GetString(2 + 2 * index);
+    menuItemNode.setAttribute("value", index);
+    menuItemNode.setAttribute("label", nick); // this is displayed
+    selectElement.firstChild.appendChild(menuItemNode);
+    if (index == 0) {
+      selectElement.selectedItem = menuItemNode;
+    }
+  }
+  setDetails();
+  document.getElementById("pw").focus();
+}
+
+function setDetails()
+{
+  var index = parseInt(document.getElementById("nicknames").value);
+  if (index == "NaN")
+    return;
+  
+  var details = dialogParams.GetString(2 + (2 * index + 1));
+  document.getElementById("certdetails").value = details;
+}
+
+function onCertSelected()
+{
+  setDetails();
+}
+
+function doOK()
+{
+  dialogParams.SetInt(0, 1);
+  var index = parseInt(document.getElementById("nicknames").value);
+  dialogParams.SetInt(1, index);
+  var password = document.getElementById("pw").value;
+  dialogParams.SetString(0, password);
+  return true;
+}
+
+function doCancel()
+{
+  dialogParams.SetInt(0, 0);
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/pki/resources/content/formsigning.xul
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!-- 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/. -->
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % pippkiDTD SYSTEM "chrome://pippki/locale/pippki.dtd" >
+%pippkiDTD;
+]>
+
+<dialog id="formsigning" title="Text Signing Request"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  buttons="accept,cancel"
+  ondialogaccept="return doOK();"
+  ondialogcancel="return doCancel();"
+  onload="onLoad();">
+
+<stringbundle id="pippki_bundle" src="chrome://pippki/locale/pippki.properties"/>
+
+<script type="application/javascript" src="chrome://pippki/content/pippki.js"/>
+<script type="application/javascript" src="chrome://pippki/content/formsigning.js"/>
+
+  <description id="sign.intro" style="max-width: 50em;"/>
+  <textbox readonly="true" id="sign.text" multiline="true"
+    style="height: 10em;" wrap="off"/>
+  <separator class="thin"/>
+  <groupbox>
+    <caption label="Signing Certificate"/>
+    <broadcaster id="certSelected" oncommand="onCertSelected();"/>
+    <menulist id="nicknames" observes="certSelected">
+      <!-- The items in this menulist must never be sorted,
+           but remain in the order filled by the application
+      -->
+      <menupopup/>
+    </menulist>
+    <textbox readonly="true" id="certdetails" multiline="true"
+      style="height: 10em;" wrap="off"/>
+    <separator/>
+  </groupbox>
+  <separator class="thin"/>
+  <description style="max-width: 30em;">To confirm you agree to sign this text message using your selected certificate, please confirm by entering the master password:</description>
+  <textbox id="pw" type="password"/>
+</dialog>
--- a/security/manager/pki/resources/jar.mn
+++ b/security/manager/pki/resources/jar.mn
@@ -42,8 +42,10 @@ pippki.jar:
     content/pippki/choosetoken.xul           (content/choosetoken.xul)
     content/pippki/choosetoken.js            (content/choosetoken.js)
     content/pippki/escrowWarn.xul            (content/escrowWarn.xul)
     content/pippki/escrowWarn.js             (content/escrowWarn.js)
     content/pippki/createCertInfo.xul        (content/createCertInfo.xul)
     content/pippki/createCertInfo.js         (content/createCertInfo.js)
     content/pippki/protectedAuth.xul         (content/protectedAuth.xul)
     content/pippki/protectedAuth.js          (content/protectedAuth.js)
+    content/pippki/formsigning.xul           (content/formsigning.xul)
+    content/pippki/formsigning.js            (content/formsigning.js)
--- a/security/manager/pki/src/moz.build
+++ b/security/manager/pki/src/moz.build
@@ -1,16 +1,17 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=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/.
 
 UNIFIED_SOURCES += [
     'nsASN1Tree.cpp',
+    'nsFormSigningDialog.cpp',
     'nsNSSDialogHelper.cpp',
     'nsNSSDialogs.cpp',
     'nsPKIModule.cpp',
     'nsPKIParamBlock.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
new file mode 100644
--- /dev/null
+++ b/security/manager/pki/src/nsFormSigningDialog.cpp
@@ -0,0 +1,91 @@
+/* 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/. */
+
+#include "nsFormSigningDialog.h"
+#include "nsNSSDialogHelper.h"
+#include "nsCOMPtr.h"
+#include "nsIDialogParamBlock.h"
+#include "nsIComponentManager.h"
+#include "nsIServiceManager.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsLiteralString.h"
+#include "nsXPIDLString.h"
+
+nsFormSigningDialog::nsFormSigningDialog()
+{
+}
+
+nsFormSigningDialog::~nsFormSigningDialog()
+{
+}
+
+NS_IMPL_ISUPPORTS(nsFormSigningDialog, nsIFormSigningDialog)
+
+NS_IMETHODIMP
+nsFormSigningDialog::ConfirmSignText(nsIInterfaceRequestor *aContext, 
+                                     const nsAString &aHost,
+                                     const nsAString &aSignText,
+                                     const char16_t **aCertNickList,
+                                     const char16_t **aCertDetailsList,
+                                     uint32_t aCount, int32_t *aSelectedIndex,
+                                     nsAString &aPassword, bool *aCanceled) 
+{
+  *aCanceled = true;
+
+  // Get the parent window for the dialog
+  nsCOMPtr<nsIDOMWindow> parent = do_GetInterface(aContext);
+
+  nsresult rv;
+  nsCOMPtr<nsIDialogParamBlock> block =
+    do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  block->SetNumberStrings(3 + aCount * 2);
+
+  rv = block->SetString(0, PromiseFlatString(aHost).get());
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = block->SetString(1, PromiseFlatString(aSignText).get());
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  uint32_t i;
+  for (i = 0; i < aCount; ++i) {
+    rv = block->SetString(2 + 2 * i, aCertNickList[i]);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = block->SetString(2 + (2 * i + 1), aCertDetailsList[i]);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  rv = block->SetInt(0, aCount);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = nsNSSDialogHelper::openDialog(parent,
+                                     "chrome://pippki/content/formsigning.xul",
+                                     block);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  int32_t status;
+  rv = block->GetInt(0, &status);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (status == 0) {
+    *aCanceled = true;
+  }
+  else {
+    *aCanceled = false;
+
+    rv = block->GetInt(1, aSelectedIndex);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsXPIDLString pw;
+    rv = block->GetString(0, getter_Copies(pw));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    aPassword = pw;
+  }
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/pki/src/nsFormSigningDialog.h
@@ -0,0 +1,26 @@
+/* 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/. */
+
+#ifndef __NS_NSFORMSIGNINGDIALOG_H__
+#define __NS_NSFORMSIGNINGDIALOG_H__
+
+#include "nsIFormSigningDialog.h"
+#include "mozilla/Attributes.h"
+
+#define NS_FORMSIGNINGDIALOG_CID \
+  { 0xa4bd2161, 0x7892, 0x4389, \
+    { 0x8d, 0x5a, 0x31, 0x11, 0xa6, 0xd1, 0x7e, 0xc7 }}
+
+class nsFormSigningDialog MOZ_FINAL : public nsIFormSigningDialog
+{
+private:
+  ~nsFormSigningDialog();
+public:
+  nsFormSigningDialog();
+
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIFORMSIGNINGDIALOG
+};
+
+#endif
--- a/security/manager/pki/src/nsPKIModule.cpp
+++ b/security/manager/pki/src/nsPKIModule.cpp
@@ -4,43 +4,48 @@
  * 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/. */
 
 #include "mozilla/ModuleUtils.h"
 
 #include "nsNSSDialogs.h"
 #include "nsPKIParamBlock.h"
 #include "nsASN1Tree.h"
+#include "nsFormSigningDialog.h"
 
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNSSDialogs, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPKIParamBlock, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsNSSASN1Tree)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsFormSigningDialog)
 
 NS_DEFINE_NAMED_CID(NS_NSSDIALOGS_CID);
 NS_DEFINE_NAMED_CID(NS_NSSASN1OUTINER_CID);
 NS_DEFINE_NAMED_CID(NS_PKIPARAMBLOCK_CID);
+NS_DEFINE_NAMED_CID(NS_FORMSIGNINGDIALOG_CID);
 
 
 static const mozilla::Module::CIDEntry kPKICIDs[] = {
   { &kNS_NSSDIALOGS_CID, false, nullptr, nsNSSDialogsConstructor },
   { &kNS_NSSASN1OUTINER_CID, false, nullptr, nsNSSASN1TreeConstructor },
   { &kNS_PKIPARAMBLOCK_CID, false, nullptr, nsPKIParamBlockConstructor },
+  { &kNS_FORMSIGNINGDIALOG_CID, false, nullptr, nsFormSigningDialogConstructor },
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kPKIContracts[] = {
   { NS_TOKENPASSWORDSDIALOG_CONTRACTID, &kNS_NSSDIALOGS_CID },
   { NS_CERTIFICATEDIALOGS_CONTRACTID, &kNS_NSSDIALOGS_CID },
   { NS_CLIENTAUTHDIALOGS_CONTRACTID, &kNS_NSSDIALOGS_CID },
   { NS_CERTPICKDIALOGS_CONTRACTID, &kNS_NSSDIALOGS_CID },
   { NS_TOKENDIALOGS_CONTRACTID, &kNS_NSSDIALOGS_CID },
   { NS_DOMCRYPTODIALOGS_CONTRACTID, &kNS_NSSDIALOGS_CID },
   { NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID, &kNS_NSSDIALOGS_CID },
   { NS_ASN1TREE_CONTRACTID, &kNS_NSSASN1OUTINER_CID },
   { NS_PKIPARAMBLOCK_CONTRACTID, &kNS_PKIPARAMBLOCK_CID },
+  { NS_FORMSIGNINGDIALOG_CONTRACTID, &kNS_FORMSIGNINGDIALOG_CID },
   { nullptr }
 };
 
 static const mozilla::Module kPKIModule = {
   mozilla::Module::kVersion,
   kPKICIDs,
   kPKIContracts
 };
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/crashtests/327524-1.html
@@ -0,0 +1,10 @@
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+
+<title>Testcase bug 327524 - Crash when using crypto.generateCRMFRequest(document.documentElement);</title>
+</head><body>
+This should not crash Mozilla
+<script>
+crypto.generateCRMFRequest(document.documentElement);
+</script>
+</body></html>
\ No newline at end of file
--- a/security/manager/ssl/crashtests/crashtests.list
+++ b/security/manager/ssl/crashtests/crashtests.list
@@ -1,1 +1,2 @@
+skip-if(browserIsRemote) asserts-if(browserIsRemote,0-1) load 327524-1.html # bug 582297, bug 918119
 asserts-if(browserIsRemote,1) load 398665-1.html # bug 582297
--- a/security/manager/ssl/public/moz.build
+++ b/security/manager/ssl/public/moz.build
@@ -12,16 +12,17 @@ XPIDL_SOURCES += [
     'nsIBadCertListener2.idl',
     'nsICertificateDialogs.idl',
     'nsICertificatePrincipal.idl',
     'nsICertOverrideService.idl',
     'nsICertPickDialogs.idl',
     'nsIClientAuthDialogs.idl',
     'nsIDataSignatureVerifier.idl',
     'nsIDOMCryptoDialogs.idl',
+    'nsIFormSigningDialog.idl',
     'nsIGenKeypairInfoDlg.idl',
     'nsIIdentityInfo.idl',
     'nsIKeygenThread.idl',
     'nsIKeyModule.idl',
     'nsINSSCertCache.idl',
     'nsINSSVersion.idl',
     'nsIPK11Token.idl',
     'nsIPK11TokenDB.idl',
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/public/nsIFormSigningDialog.idl
@@ -0,0 +1,39 @@
+/* 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/. */
+
+#include "nsISupports.idl"
+
+interface nsIInterfaceRequestor;
+
+/**
+ * nsIFormSigningDialog
+ * Provides UI for form signing.
+ */
+[scriptable, uuid(4fe04d6d-4b66-4023-a0bc-b43ce68b3e15)]
+interface nsIFormSigningDialog : nsISupports
+{
+  /**
+   *  confirmSignText
+   *    UI shown when a web site calls crypto.signText,
+   *    asking the user to confirm the confirm the signing request.
+   *
+   *  returns true if the user confirmed, false on cancel
+   */
+  boolean confirmSignText(in nsIInterfaceRequestor ctxt,
+                          in AString host,
+                          in AString signText,
+                          [array, size_is(count)] in wstring certNickList,
+                          [array, size_is(count)] in wstring certDetailsList,
+                          in uint32_t count,
+                          out int32_t selectedIndex,
+                          out AString password);
+};
+
+/**
+ * NS_FORMSIGNINGDIALOG_CONTRACTID - contract id to obtain an instance
+ *   that implements nsIFormSigningDialog.
+ */
+%{C++
+#define NS_FORMSIGNINGDIALOG_CONTRACTID "@mozilla.org/nsFormSigningDialog;1"
+%}
--- a/security/manager/ssl/src/moz.build
+++ b/security/manager/ssl/src/moz.build
@@ -68,17 +68,17 @@ SOURCES += [
 SOURCES += [
     'nsCryptoHash.cpp',
     'nsNSSCertificateDB.cpp',
     'nsNSSComponent.cpp',
     'nsNSSVersion.cpp',
     'PSMContentListener.cpp',
 ]
 
-if not CONFIG['MOZ_NO_SMART_CARDS']:
+if not CONFIG['MOZ_DISABLE_CRYPTOLEGACY']:
     SOURCES += [
         'nsSmartCardMonitor.cpp',
     ]
 
 if CONFIG['MOZ_XUL']:
     SOURCES += [
         'nsCertTree.cpp',
     ]
--- a/security/manager/ssl/src/nsCrypto.cpp
+++ b/security/manager/ssl/src/nsCrypto.cpp
@@ -9,25 +9,2817 @@
 
 #include "nsReadableUtils.h"
 #include "nsCRT.h"
 #include "nsXPIDLString.h"
 #include "nsISaveAsCharset.h"
 #include "nsNativeCharsetUtils.h"
 #include "nsServiceManagerUtils.h"
 
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+#include "mozilla/dom/ScriptSettings.h"
+#include "nsKeygenHandler.h"
+#include "nsKeygenThread.h"
+#include "nsNSSCertificate.h"
+#include "nsNSSCertificateDB.h"
+#include "nsPKCS12Blob.h"
+#include "nsPK11TokenDB.h"
+#include "nsThreadUtils.h"
+#include "nsIServiceManager.h"
+#include "nsIMemory.h"
+#include "nsAlgorithm.h"
+#include "prprf.h"
+#include "nsDOMCID.h"
+#include "nsIDOMWindow.h"
+#include "nsIDOMClassInfo.h"
+#include "nsIDOMDocument.h"
+#include "nsIDocument.h"
+#include "nsIScriptObjectPrincipal.h"
+#include "nsIScriptContext.h"
+#include "nsIGlobalObject.h"
+#include "nsContentUtils.h"
+#include "nsDOMJSUtils.h"
+#include "nsJSUtils.h"
+#include "nsIXPConnect.h"
+#include "nsIRunnable.h"
+#include "nsIWindowWatcher.h"
+#include "nsIPrompt.h"
+#include "nsIFilePicker.h"
+#include "nsJSPrincipals.h"
+#include "nsJSUtils.h"
+#include "nsIPrincipal.h"
+#include "nsIScriptSecurityManager.h"
+#include "nsIGenKeypairInfoDlg.h"
+#include "nsIDOMCryptoDialogs.h"
+#include "nsIFormSigningDialog.h"
+#include "nsIContentSecurityPolicy.h"
+#include "nsIURI.h"
+#include "jsapi.h"
+#include "js/OldDebugAPI.h"
+#include <ctype.h>
+#include "pk11func.h"
+#include "keyhi.h"
+#include "cryptohi.h"
+#include "seccomon.h"
+#include "secerr.h"
+#include "sechash.h"
+#include "crmf.h"
+#include "pk11pqg.h"
+#include "cmmf.h"
+#include "nssb64.h"
+#include "base64.h"
+#include "cert.h"
+#include "certdb.h"
+#include "secmod.h"
+#include "ScopedNSSTypes.h"
+#include "pkix/pkixtypes.h"
+
+#include "ssl.h" // For SSL_ClearSessionCache
+
+#include "nsNSSCleaner.h"
+
+#include "nsNSSCertHelper.h"
+#include <algorithm>
+#include "nsWrapperCacheInlines.h"
+#endif
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+#include "mozilla/dom/CRMFObjectBinding.h"
+#endif
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+/*
+ * These are the most common error strings that are returned
+ * by the JavaScript methods in case of error.
+ */
+
+#define JS_ERROR       "error:"
+#define JS_ERROR_INTERNAL  JS_ERROR"internalError"
+
+#undef REPORT_INCORRECT_NUM_ARGS
+
+#define JS_OK_ADD_MOD                      3
+#define JS_OK_DEL_EXTERNAL_MOD             2
+#define JS_OK_DEL_INTERNAL_MOD             1
+
+#define JS_ERR_INTERNAL                   -1
+#define JS_ERR_USER_CANCEL_ACTION         -2
+#define JS_ERR_INCORRECT_NUM_OF_ARGUMENTS -3
+#define JS_ERR_DEL_MOD                    -4
+#define JS_ERR_ADD_MOD                    -5
+#define JS_ERR_BAD_MODULE_NAME            -6
+#define JS_ERR_BAD_DLL_NAME               -7
+#define JS_ERR_BAD_MECHANISM_FLAGS        -8
+#define JS_ERR_BAD_CIPHER_ENABLE_FLAGS    -9
+#define JS_ERR_ADD_DUPLICATE_MOD          -10
+
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+
+NSSCleanupAutoPtrClass_WithParam(PK11Context, PK11_DestroyContext, TrueParam, true)
+
+/*
+ * This structure is used to store information for one key generation.
+ * The nsCrypto::GenerateCRMFRequest method parses the inputs and then
+ * stores one of these structures for every key generation that happens.
+ * The information stored in this structure is then used to set some
+ * values in the CRMF request.
+ */
+typedef enum {
+  rsaEnc, rsaDualUse, rsaSign, rsaNonrepudiation, rsaSignNonrepudiation,
+  ecEnc, ecDualUse, ecSign, ecNonrepudiation, ecSignNonrepudiation,
+  dhEx, dsaSignNonrepudiation, dsaSign, dsaNonrepudiation, invalidKeyGen
+} nsKeyGenType;
+
+bool isECKeyGenType(nsKeyGenType kgt)
+{
+  switch (kgt)
+  {
+    case ecEnc:
+    case ecDualUse:
+    case ecSign:
+    case ecNonrepudiation:
+    case ecSignNonrepudiation:
+      return true;
+    
+    default:
+      break;
+  }
+
+  return false;
+}
+
+typedef struct nsKeyPairInfoStr {
+  SECKEYPublicKey  *pubKey;     /* The putlic key associated with gen'd 
+                                   priv key. */
+  SECKEYPrivateKey *privKey;    /* The private key we generated */ 
+  nsKeyGenType      keyGenType; /* What type of key gen are we doing.*/
+
+  CERTCertificate *ecPopCert;
+                   /* null: use signing for pop
+                      other than null: a cert that defines EC keygen params
+                                       and will be used for dhMac PoP. */
+
+  SECKEYPublicKey  *ecPopPubKey;
+                   /* extracted public key from ecPopCert */
+} nsKeyPairInfo;
+
+
+//This class is just used to pass arguments
+//to the nsCryptoRunnable event.
+class nsCryptoRunArgs : public nsISupports {
+public:
+  nsCryptoRunArgs();
+  nsCOMPtr<nsIGlobalObject> m_globalObject;
+  nsXPIDLCString m_jsCallback;
+  NS_DECL_ISUPPORTS
+protected:
+  virtual ~nsCryptoRunArgs();
+};
+
+//This class is used to run the callback code
+//passed to crypto.generateCRMFRequest
+//We have to do that for backwards compatibility
+//reasons w/ PSM 1.x and Communciator 4.x
+class nsCryptoRunnable : public nsIRunnable {
+public:
+  nsCryptoRunnable(nsCryptoRunArgs *args);
+
+  NS_IMETHOD Run ();
+  NS_DECL_ISUPPORTS
+private:
+  virtual ~nsCryptoRunnable();
+
+  nsCryptoRunArgs *m_args;
+};
+
+//We're going to inherit the memory passed
+//into us.
+//This class backs up an array of certificates
+//as an event.
+class nsP12Runnable : public nsIRunnable {
+public:
+  nsP12Runnable(nsIX509Cert **certArr, int32_t numCerts, nsIPK11Token *token);
+
+  NS_IMETHOD Run();
+  NS_DECL_ISUPPORTS
+protected:
+  virtual ~nsP12Runnable();
+private:
+  nsCOMPtr<nsIPK11Token> mToken;
+  nsIX509Cert **mCertArr;
+  int32_t       mNumCerts;
+};
+
+// QueryInterface implementation for nsCrypto
+NS_INTERFACE_MAP_BEGIN(nsCrypto)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMCrypto)
+NS_INTERFACE_MAP_END_INHERITING(mozilla::dom::Crypto)
+
+NS_IMPL_ADDREF_INHERITED(nsCrypto, mozilla::dom::Crypto)
+NS_IMPL_RELEASE_INHERITED(nsCrypto, mozilla::dom::Crypto)
+
 // QueryInterface implementation for nsPkcs11
+#endif // MOZ_DISABLE_CRYPTOLEGACY
+
 NS_INTERFACE_MAP_BEGIN(nsPkcs11)
   NS_INTERFACE_MAP_ENTRY(nsIPKCS11)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsPkcs11)
 NS_IMPL_RELEASE(nsPkcs11)
 
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+
+// ISupports implementation for nsCryptoRunnable
+NS_IMPL_ISUPPORTS(nsCryptoRunnable, nsIRunnable)
+
+// ISupports implementation for nsP12Runnable
+NS_IMPL_ISUPPORTS(nsP12Runnable, nsIRunnable)
+
+// ISupports implementation for nsCryptoRunArgs
+NS_IMPL_ISUPPORTS0(nsCryptoRunArgs)
+
+nsCrypto::nsCrypto() :
+  mEnableSmartCardEvents(false)
+{
+}
+
+nsCrypto::~nsCrypto()
+{
+}
+
+void
+nsCrypto::Init(nsIDOMWindow* aWindow)
+{
+  mozilla::dom::Crypto::Init(aWindow);
+}
+
+void
+nsCrypto::SetEnableSmartCardEvents(bool aEnable, ErrorResult& aRv)
+{
+  NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
+
+  nsresult rv = NS_OK;
+
+  // this has the side effect of starting the nssComponent (and initializing
+  // NSS) even if it isn't already going. Starting the nssComponent is a
+  // prerequisite for getting smartCard events.
+  if (aEnable) {
+    nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
+  }
+
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return;
+  }
+
+  mEnableSmartCardEvents = aEnable;
+}
+
+NS_IMETHODIMP
+nsCrypto::SetEnableSmartCardEvents(bool aEnable)
+{
+  ErrorResult rv;
+  SetEnableSmartCardEvents(aEnable, rv);
+  return rv.ErrorCode();
+}
+
+bool
+nsCrypto::EnableSmartCardEvents()
+{
+  return mEnableSmartCardEvents;
+}
+
+NS_IMETHODIMP
+nsCrypto::GetEnableSmartCardEvents(bool *aEnable)
+{
+  *aEnable = EnableSmartCardEvents();
+  return NS_OK;
+}
+
+//A quick function to let us know if the key we're trying to generate
+//can be escrowed.
+static bool
+ns_can_escrow(nsKeyGenType keyGenType)
+{
+  /* For now, we only escrow rsa-encryption and ec-encryption keys. */
+  return (bool)(keyGenType == rsaEnc || keyGenType == ecEnc);
+}
+
+//Retrieve crypto.version so that callers know what
+//version of PSM this is.
+void
+nsCrypto::GetVersion(nsString& aVersion)
+{
+  aVersion.Assign(NS_LITERAL_STRING(PSM_VERSION_STRING));
+}
+
+/*
+ * Given an nsKeyGenType, return the PKCS11 mechanism that will
+ * perform the correct key generation.
+ */
+static uint32_t
+cryptojs_convert_to_mechanism(nsKeyGenType keyGenType)
+{
+  uint32_t retMech;
+
+  switch (keyGenType) {
+  case rsaEnc:
+  case rsaDualUse:
+  case rsaSign:
+  case rsaNonrepudiation:
+  case rsaSignNonrepudiation:
+    retMech = CKM_RSA_PKCS_KEY_PAIR_GEN;
+    break;
+  case ecEnc:
+  case ecDualUse:
+  case ecSign:
+  case ecNonrepudiation:
+  case ecSignNonrepudiation:
+    retMech = CKM_EC_KEY_PAIR_GEN;
+    break;
+  case dhEx:
+    retMech = CKM_DH_PKCS_KEY_PAIR_GEN;
+    break;
+  case dsaSign:
+  case dsaSignNonrepudiation:
+  case dsaNonrepudiation:
+    retMech = CKM_DSA_KEY_PAIR_GEN;
+    break;
+  default:
+    retMech = CKM_INVALID_MECHANISM;
+  }
+  return retMech;
+}
+
+/*
+ * This function takes a string read through JavaScript parameters
+ * and translates it to the internal enumeration representing the
+ * key gen type. Leading and trailing whitespace must be already removed.
+ */
+static nsKeyGenType
+cryptojs_interpret_key_gen_type(const nsAString& keyAlg)
+{
+  if (keyAlg.EqualsLiteral("rsa-ex")) {
+    return rsaEnc;
+  }
+  if (keyAlg.EqualsLiteral("rsa-dual-use")) {
+    return rsaDualUse;
+  }
+  if (keyAlg.EqualsLiteral("rsa-sign")) {
+    return rsaSign;
+  }
+  if (keyAlg.EqualsLiteral("rsa-sign-nonrepudiation")) {
+    return rsaSignNonrepudiation;
+  }
+  if (keyAlg.EqualsLiteral("rsa-nonrepudiation")) {
+    return rsaNonrepudiation;
+  }
+  if (keyAlg.EqualsLiteral("ec-ex")) {
+    return ecEnc;
+  }
+  if (keyAlg.EqualsLiteral("ec-dual-use")) {
+    return ecDualUse;
+  }
+  if (keyAlg.EqualsLiteral("ec-sign")) {
+    return ecSign;
+  }
+  if (keyAlg.EqualsLiteral("ec-sign-nonrepudiation")) {
+    return ecSignNonrepudiation;
+  }
+  if (keyAlg.EqualsLiteral("ec-nonrepudiation")) {
+    return ecNonrepudiation;
+  }
+  if (keyAlg.EqualsLiteral("dsa-sign-nonrepudiation")) {
+    return dsaSignNonrepudiation;
+  }
+  if (keyAlg.EqualsLiteral("dsa-sign")) {
+    return dsaSign;
+  }
+  if (keyAlg.EqualsLiteral("dsa-nonrepudiation")) {
+    return dsaNonrepudiation;
+  }
+  if (keyAlg.EqualsLiteral("dh-ex")) {
+    return dhEx;
+  }
+  return invalidKeyGen;
+}
+
+/* 
+ * input: null terminated char* pointing to (the remainder of) an
+ * EC key param string.
+ *
+ * bool return value, false means "no more name=value pair found",
+ *                    true means "found, see out params"
+ * 
+ * out param name: char * pointing to name (not zero terminated)
+ * out param name_len: length of found name
+ * out param value: char * pointing to value (not zero terminated)
+ * out param value_len: length of found value
+ * out param next_pair: to be used for a follow up call to this function
+ */
+
+bool getNextNameValueFromECKeygenParamString(char *input,
+                                               char *&name,
+                                               int &name_len,
+                                               char *&value,
+                                               int &value_len,
+                                               char *&next_call)
+{
+  if (!input || !*input)
+    return false;
+
+  // we allow leading ; and leading space in front of each name value pair
+
+  while (*input && *input == ';')
+    ++input;
+
+  while (*input && *input == ' ')
+    ++input;
+
+  name = input;
+
+  while (*input && *input != '=')
+    ++input;
+
+  if (*input != '=')
+    return false;
+
+  name_len = input - name;
+  ++input;
+
+  value = input;
+
+  while (*input && *input != ';')
+    ++input;
+
+  value_len = input - value;
+  next_call = input;
+
+  return true;
+}
+
+//Take the string passed into us via crypto.generateCRMFRequest
+//as the keygen type parameter and convert it to parameters 
+//we can actually pass to the PKCS#11 layer.
+static void*
+nsConvertToActualKeyGenParams(uint32_t keyGenMech, char *params,
+                              uint32_t paramLen, int32_t keySize,
+                              nsKeyPairInfo *keyPairInfo)
+{
+  void *returnParams = nullptr;
+
+
+  switch (keyGenMech) {
+  case CKM_RSA_PKCS_KEY_PAIR_GEN:
+  {
+    // For RSA, we don't support passing in key generation arguments from
+    // the JS code just yet.
+    if (params)
+      return nullptr;
+
+    PK11RSAGenParams *rsaParams;
+    rsaParams = static_cast<PK11RSAGenParams*>
+                           (nsMemory::Alloc(sizeof(PK11RSAGenParams)));
+                              
+    if (!rsaParams) {
+      return nullptr;
+    }
+    /* I'm just taking the same parameters used in 
+     * certdlgs.c:GenKey
+     */
+    if (keySize > 0) {
+      rsaParams->keySizeInBits = keySize;
+    } else {
+      rsaParams->keySizeInBits = 1024;
+    }
+    rsaParams->pe = DEFAULT_RSA_KEYGEN_PE;
+    returnParams = rsaParams;
+    break;
+  }
+  case CKM_EC_KEY_PAIR_GEN:
+  {
+    /*
+     * keygen params for generating EC keys must be composed of name=value pairs,
+     * multiple pairs allowed, separated using semicolon ;
+     *
+     * Either param "curve" or param "popcert" must be specified.
+     * curve=name-of-curve
+     * popcert=base64-encoded-cert
+     *
+     * When both params are specified, popcert will be used.
+     * If no popcert param is given, or if popcert can not be decoded,
+     * we will fall back to the curve param.
+     *
+     * Additional name=value pairs may be defined in the future.
+     *
+     * If param popcert is present and valid, the given certificate will be used
+     * to determine the key generation params. In addition the certificate
+     * will be used to produce a dhMac based Proof of Posession,
+     * using the cert's public key, subject and issuer names,
+     * as specified in RFC 2511 section 4.3 paragraph 2 and Appendix A.
+     *
+     * If neither param popcert nor param curve could be used,
+     * tse a curve based on the keysize param.
+     * NOTE: Here keysize is used only as an indication of
+     * High/Medium/Low strength; elliptic curve
+     * cryptography uses smaller keys than RSA to provide
+     * equivalent security.
+     */
+
+    char *curve = nullptr;
+
+    {
+      // extract components of name=value list
+
+      char *next_input = params;
+      char *name = nullptr;
+      char *value = nullptr;
+      int name_len = 0;
+      int value_len = 0;
+  
+      while (getNextNameValueFromECKeygenParamString(
+              next_input, name, name_len, value, value_len,
+              next_input))
+      {
+        // use only the first specified curve
+        if (!curve && PL_strncmp(name, "curve", std::min(name_len, 5)) == 0)
+        {
+          curve = PL_strndup(value, value_len);
+        }
+        // use only the first specified popcert
+        else if (!keyPairInfo->ecPopCert &&
+                 PL_strncmp(name, "popcert", std::min(name_len, 7)) == 0)
+        {
+          char *certstr = PL_strndup(value, value_len);
+          if (certstr) {
+            keyPairInfo->ecPopCert = CERT_ConvertAndDecodeCertificate(certstr);
+            PL_strfree(certstr);
+
+            if (keyPairInfo->ecPopCert)
+            {
+              keyPairInfo->ecPopPubKey = CERT_ExtractPublicKey(keyPairInfo->ecPopCert);
+            }
+          }
+        }
+      }
+    }
+
+    // first try to use the params of the provided CA cert
+    if (keyPairInfo->ecPopPubKey && keyPairInfo->ecPopPubKey->keyType == ecKey)
+    {
+      returnParams = SECITEM_DupItem(&keyPairInfo->ecPopPubKey->u.ec.DEREncodedParams);
+    }
+
+    // if we did not yet find good params, do we have a curve name?
+    if (!returnParams && curve)
+    {
+      returnParams = decode_ec_params(curve);
+    }
+
+    // if we did not yet find good params, do something based on keysize
+    if (!returnParams)
+    {
+      switch (keySize) {
+      case 512:
+      case 1024:
+          returnParams = decode_ec_params("secp256r1");
+          break;
+      case 2048:
+      default:
+          returnParams = decode_ec_params("secp384r1");
+          break;
+      }
+    }
+
+    if (curve)
+      PL_strfree(curve);
+
+    break;
+  }
+  case CKM_DSA_KEY_PAIR_GEN:
+  {
+    // For DSA, we don't support passing in key generation arguments from
+    // the JS code just yet.
+    if (params)
+      return nullptr;
+
+    PQGParams *pqgParams = nullptr;
+    PQGVerify *vfy = nullptr;
+    SECStatus  rv;
+    int        index;
+       
+    index = PQG_PBITS_TO_INDEX(keySize);
+    if (index == -1) {
+      returnParams = nullptr;
+      break;
+    }
+    rv = PK11_PQG_ParamGen(0, &pqgParams, &vfy);
+    if (vfy) {
+      PK11_PQG_DestroyVerify(vfy);
+    }
+    if (rv != SECSuccess) {
+      if (pqgParams) {
+        PK11_PQG_DestroyParams(pqgParams);
+      }
+      return nullptr;
+    }
+    returnParams = pqgParams;
+    break;
+  }
+  default:
+    returnParams = nullptr;
+  }
+  return returnParams;
+}
+
+//We need to choose which PKCS11 slot we're going to generate
+//the key on.  Calls the default implementation provided by
+//nsKeygenHandler.cpp
+static PK11SlotInfo*
+nsGetSlotForKeyGen(nsKeyGenType keyGenType, nsIInterfaceRequestor *ctx)
+{
+  nsNSSShutDownPreventionLock locker;
+  uint32_t mechanism = cryptojs_convert_to_mechanism(keyGenType);
+  PK11SlotInfo *slot = nullptr;
+  nsresult rv = GetSlotWithMechanism(mechanism,ctx, &slot);
+  if (NS_FAILED(rv)) {
+    if (slot)
+      PK11_FreeSlot(slot);
+    slot = nullptr;
+  }
+  return slot;
+}
+
+//Free the parameters that were passed into PK11_GenerateKeyPair
+//depending on the mechanism type used.
+static void
+nsFreeKeyGenParams(CK_MECHANISM_TYPE keyGenMechanism, void *params)
+{
+  switch (keyGenMechanism) {
+  case CKM_RSA_PKCS_KEY_PAIR_GEN:
+    nsMemory::Free(params);
+    break;
+  case CKM_EC_KEY_PAIR_GEN:
+    SECITEM_FreeItem(reinterpret_cast<SECItem*>(params), true);
+    break;
+  case CKM_DSA_KEY_PAIR_GEN:
+    PK11_PQG_DestroyParams(static_cast<PQGParams*>(params));
+    break;
+  }
+}
+
+//Function that is used to generate a single key pair.
+//Once all the arguments have been parsed and processed, this
+//function gets called and takes care of actually generating
+//the key pair passing the appopriate parameters to the NSS
+//functions.
+static nsresult
+cryptojs_generateOneKeyPair(JSContext *cx, nsKeyPairInfo *keyPairInfo, 
+                            int32_t keySize, char *params, 
+                            nsIInterfaceRequestor *uiCxt,
+                            PK11SlotInfo *slot, bool willEscrow)
+                            
+{
+  const PK11AttrFlags sensitiveFlags = (PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE);
+  const PK11AttrFlags temporarySessionFlags = PK11_ATTR_SESSION;
+  const PK11AttrFlags permanentTokenFlags = PK11_ATTR_TOKEN;
+  const PK11AttrFlags extractableFlags = PK11_ATTR_EXTRACTABLE;
+  
+  nsIGeneratingKeypairInfoDialogs * dialogs;
+  nsKeygenThread *KeygenRunnable = 0;
+  nsCOMPtr<nsIKeygenThread> runnable;
+
+  uint32_t mechanism = cryptojs_convert_to_mechanism(keyPairInfo->keyGenType);
+  void *keyGenParams = nsConvertToActualKeyGenParams(mechanism, params, 
+                                                     (params) ? strlen(params):0, 
+                                                     keySize, keyPairInfo);
+
+  if (!keyGenParams || !slot) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  // Make sure the token has password already set on it before trying
+  // to generate the key.
+
+  nsresult rv = setPassword(slot, uiCxt);
+  if (NS_FAILED(rv))
+    return rv;
+
+  if (PK11_Authenticate(slot, true, uiCxt) != SECSuccess)
+    return NS_ERROR_FAILURE;
+ 
+  // Smart cards will not let you extract a private key once 
+  // it is on the smart card.  If we've been told to escrow
+  // a private key that will be stored on a smart card,
+  // then we'll use the following strategy to ensure we can escrow it.
+  // We'll attempt to generate the key on our internal token,
+  // because this is expected to avoid some problems.
+  // If it works, we'll escrow, move the key to the smartcard, done.
+  // If it didn't work (or the internal key doesn't support the desired
+  // mechanism), then we'll attempt to generate the key on
+  // the destination token, with the EXTRACTABLE flag set.
+  // If it works, we'll extract, escrow, done.
+  // If it failed, then we're unable to escrow and return failure.
+  // NOTE: We call PK11_GetInternalSlot instead of PK11_GetInternalKeySlot
+  //       so that the key has zero chance of being store in the
+  //       user's key3.db file.  Which the slot returned by
+  //       PK11_GetInternalKeySlot has access to and PK11_GetInternalSlot
+  //       does not.
+  ScopedPK11SlotInfo intSlot;
+  
+  if (willEscrow && !PK11_IsInternal(slot)) {
+    intSlot = PK11_GetInternalSlot();
+    NS_ASSERTION(intSlot,"Couldn't get the internal slot");
+    
+    if (!PK11_DoesMechanism(intSlot, mechanism)) {
+      // Set to null, and the subsequent code will not attempt to use it.
+      intSlot = nullptr;
+    }
+  }
+
+  rv = getNSSDialogs((void**)&dialogs,
+                     NS_GET_IID(nsIGeneratingKeypairInfoDialogs),
+                     NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID);
+
+  if (NS_SUCCEEDED(rv)) {
+    KeygenRunnable = new nsKeygenThread();
+    if (KeygenRunnable) {
+      NS_ADDREF(KeygenRunnable);
+    }
+  }
+  
+  // "firstAttemptSlot" and "secondAttemptSlot" are alternative names
+  // for better code readability, we don't increase the reference counts.
+  
+  PK11SlotInfo *firstAttemptSlot = nullptr;
+  PK11AttrFlags firstAttemptFlags = 0;
+
+  PK11SlotInfo *secondAttemptSlot = slot;
+  PK11AttrFlags secondAttemptFlags = sensitiveFlags | permanentTokenFlags;
+  
+  if (willEscrow) {
+    secondAttemptFlags |= extractableFlags;
+  }
+  
+  if (!intSlot || PK11_IsInternal(slot)) {
+    // if we cannot use the internal slot, then there is only one attempt
+    // if the destination slot is the internal slot, then there is only one attempt
+    firstAttemptSlot = secondAttemptSlot;
+    firstAttemptFlags = secondAttemptFlags;
+    secondAttemptSlot = nullptr;
+    secondAttemptFlags = 0;
+  }
+  else {
+    firstAttemptSlot = intSlot;
+    firstAttemptFlags = sensitiveFlags | temporarySessionFlags;
+    
+    // We always need the extractable flag on the first attempt,
+    // because we want to move the key to another slot - ### is this correct?
+    firstAttemptFlags |= extractableFlags;
+  }
+
+  bool mustMoveKey = false;
+  
+  if (NS_FAILED(rv) || !KeygenRunnable) {
+    /* execute key generation on this thread */
+    rv = NS_OK;
+    
+    keyPairInfo->privKey = 
+      PK11_GenerateKeyPairWithFlags(firstAttemptSlot, mechanism,
+                                    keyGenParams, &keyPairInfo->pubKey,
+                                    firstAttemptFlags, uiCxt);
+    
+    if (keyPairInfo->privKey) {
+      // success on first attempt
+      if (secondAttemptSlot) {
+        mustMoveKey = true;
+      }
+    }
+    else {
+      keyPairInfo->privKey = 
+        PK11_GenerateKeyPairWithFlags(secondAttemptSlot, mechanism,
+                                      keyGenParams, &keyPairInfo->pubKey,
+                                      secondAttemptFlags, uiCxt);
+    }
+    
+  } else {
+    /* execute key generation on separate thread */
+    KeygenRunnable->SetParams( firstAttemptSlot, firstAttemptFlags,
+                               secondAttemptSlot, secondAttemptFlags,
+                               mechanism, keyGenParams, uiCxt );
+
+    runnable = do_QueryInterface(KeygenRunnable);
+
+    if (runnable) {
+      {
+        nsPSMUITracker tracker;
+        if (tracker.isUIForbidden()) {
+          rv = NS_ERROR_NOT_AVAILABLE;
+        }
+        else {
+          rv = dialogs->DisplayGeneratingKeypairInfo(uiCxt, runnable);
+          // We call join on the thread, 
+          // so we can be sure that no simultaneous access to the passed parameters will happen.
+          KeygenRunnable->Join();
+        }
+      }
+
+      NS_RELEASE(dialogs);
+      if (NS_SUCCEEDED(rv)) {
+        PK11SlotInfo *used_slot = nullptr;
+        rv = KeygenRunnable->ConsumeResult(&used_slot, 
+                                           &keyPairInfo->privKey, &keyPairInfo->pubKey);
+
+        if (NS_SUCCEEDED(rv)) {
+          if ((used_slot == firstAttemptSlot) && secondAttemptSlot) {
+            mustMoveKey = true;
+          }
+        
+          if (used_slot) {
+            PK11_FreeSlot(used_slot);
+          }
+        }
+      }
+    }
+  }
+
+  firstAttemptSlot = nullptr;
+  secondAttemptSlot = nullptr;
+  
+  nsFreeKeyGenParams(mechanism, keyGenParams);
+
+  if (KeygenRunnable) {
+    NS_RELEASE(KeygenRunnable);
+  }
+
+  if (!keyPairInfo->privKey || !keyPairInfo->pubKey) {
+    return NS_ERROR_FAILURE;
+  }
+ 
+  //If we generated the key pair on the internal slot because the
+  // keys were going to be escrowed, move the keys over right now.
+  if (mustMoveKey) {
+    ScopedSECKEYPrivateKey newPrivKey(PK11_LoadPrivKey(slot,
+                                                    keyPairInfo->privKey,
+                                                    keyPairInfo->pubKey,
+                                                    true, true));
+    if (!newPrivKey)
+      return NS_ERROR_FAILURE;
+
+    // The private key is stored on the selected slot now, and the copy we
+    // ultimately use for escrowing when the time comes lives 
+    // in the internal slot.  We will delete it from that slot
+    // after the requests are made.
+  }  
+
+  return NS_OK;
+}
+
+/*
+ * FUNCTION: cryptojs_ReadArgsAndGenerateKey
+ * -------------------------------------
+ * INPUTS:
+ *  cx
+ *    The JSContext associated with the execution of the corresponging
+ *    crypto.generateCRMFRequest call
+ *  argv
+ *    A pointer to an array of JavaScript parameters passed to the
+ *    method crypto.generateCRMFRequest.  The array should have the
+ *    3 arguments keySize, "keyParams", and "keyGenAlg" mentioned in
+ *    the definition of crypto.generateCRMFRequest at the following
+ *    document http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html 
+ *  keyGenType
+ *    A structure used to store the information about the newly created
+ *    key pair.
+ *  uiCxt
+ *    An interface requestor that would be used to get an nsIPrompt
+ *    if we need to ask the user for a password.
+ *  slotToUse
+ *    The PKCS11 slot to use for generating the key pair. If nullptr, then
+ *    this function should select a slot that can do the key generation 
+ *    from the keytype associted with the keyPairInfo, and pass it back to
+ *    the caller so that subsequence key generations can use the same slot. 
+ *  willEscrow
+ *    If true, then that means we will try to escrow the generated
+ *    private key when building the CRMF request.  If false, then
+ *    we will not try to escrow the private key.
+ *
+ * NOTES:
+ * This function takes care of reading a set of 3 parameters that define
+ * one key generation.  The argv pointer should be one that originates
+ * from the argv parameter passed in to the method nsCrypto::GenerateCRMFRequest.
+ * The function interprets the argument in the first index as an integer and
+ * passes that as the key size for the key generation-this parameter is
+ * mandatory.  The second parameter is read in as a string.  This value can
+ * be null in JavaScript world and everything will still work.  The third
+ * parameter is a mandatory string that indicates what kind of key to generate.
+ * There should always be 1-to-1 correspondence between the strings compared
+ * in the function cryptojs_interpret_key_gen_type and the strings listed in
+ * document at http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html 
+ * under the definition of the method generateCRMFRequest, for the parameter
+ * "keyGenAlgN".  After reading the parameters, the function then 
+ * generates the key pairs passing the parameters parsed from the JavaScript i
+ * routine.  
+ *
+ * RETURN:
+ * NS_OK if creating the Key was successful.  Any other return value
+ * indicates an error.
+ */
+
+static nsresult
+cryptojs_ReadArgsAndGenerateKey(JSContext *cx,
+                                JS::Value *argv,
+                                nsKeyPairInfo *keyGenType,
+                                nsIInterfaceRequestor *uiCxt,
+                                PK11SlotInfo **slot, bool willEscrow)
+{
+  JSString  *jsString;
+  JSAutoByteString params;
+  int    keySize;
+  nsresult  rv;
+
+  if (!argv[0].isInt32()) {
+    JS_ReportError(cx, "%s%s", JS_ERROR,
+                   "passed in non-integer for key size");
+    return NS_ERROR_FAILURE;
+  }
+  keySize = argv[0].toInt32();
+  if (!argv[1].isNull()) {
+    JS::Rooted<JS::Value> v(cx, argv[1]);
+    jsString = JS::ToString(cx, v);
+    NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
+    argv[1] = STRING_TO_JSVAL(jsString);
+    params.encodeLatin1(cx, jsString);
+    NS_ENSURE_TRUE(!!params, NS_ERROR_OUT_OF_MEMORY);
+  }
+
+  if (argv[2].isNull()) {
+    JS_ReportError(cx,"%s%s", JS_ERROR,
+             "key generation type not specified");
+    return NS_ERROR_FAILURE;
+  }
+  JS::Rooted<JS::Value> v(cx, argv[2]);
+  jsString = JS::ToString(cx, v);
+  NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
+  argv[2] = STRING_TO_JSVAL(jsString);
+  nsAutoJSString autoJSKeyGenAlg;
+  NS_ENSURE_TRUE(autoJSKeyGenAlg.init(cx, jsString), NS_ERROR_UNEXPECTED);
+  nsAutoString keyGenAlg(autoJSKeyGenAlg);
+  keyGenAlg.Trim("\r\n\t ");
+  keyGenType->keyGenType = cryptojs_interpret_key_gen_type(keyGenAlg);
+  if (keyGenType->keyGenType == invalidKeyGen) {
+    NS_LossyConvertUTF16toASCII keyGenAlgNarrow(autoJSKeyGenAlg);
+    JS_ReportError(cx, "%s%s%s", JS_ERROR,
+                   "invalid key generation argument:",
+                   keyGenAlgNarrow.get());
+    goto loser;
+  }
+  if (!*slot) {
+    *slot = nsGetSlotForKeyGen(keyGenType->keyGenType, uiCxt);
+    if (!*slot)
+      goto loser;
+  }
+
+  rv = cryptojs_generateOneKeyPair(cx,keyGenType,keySize,params.ptr(),uiCxt,
+                                   *slot,willEscrow);
+
+  if (rv != NS_OK) {
+    NS_LossyConvertUTF16toASCII keyGenAlgNarrow(autoJSKeyGenAlg);
+    JS_ReportError(cx,"%s%s%s", JS_ERROR,
+                   "could not generate the key for algorithm ",
+                   keyGenAlgNarrow.get());
+    goto loser;
+  }
+  return NS_OK;
+loser:
+  return NS_ERROR_FAILURE;
+}
+
+//Utility funciton to free up the memory used by nsKeyPairInfo
+//arrays.
+static void
+nsFreeKeyPairInfo(nsKeyPairInfo *keyids, int numIDs)
+{
+  NS_ASSERTION(keyids, "NULL pointer passed to nsFreeKeyPairInfo");
+  if (!keyids)
+    return;
+  int i;
+  for (i=0; i<numIDs; i++) {
+    if (keyids[i].pubKey)
+      SECKEY_DestroyPublicKey(keyids[i].pubKey);
+    if (keyids[i].privKey)
+      SECKEY_DestroyPrivateKey(keyids[i].privKey);
+    if (keyids[i].ecPopCert)
+      CERT_DestroyCertificate(keyids[i].ecPopCert);
+    if (keyids[i].ecPopPubKey)
+      SECKEY_DestroyPublicKey(keyids[i].ecPopPubKey);
+  }
+  delete []keyids;
+}
+
+//Utility funciton used to free the genertaed cert request messages
+static void
+nsFreeCertReqMessages(CRMFCertReqMsg **certReqMsgs, int32_t numMessages)
+{
+  int32_t i;
+  for (i=0; i<numMessages && certReqMsgs[i]; i++) {
+    CRMF_DestroyCertReqMsg(certReqMsgs[i]);
+  }
+  delete []certReqMsgs;
+}
+
+//If the form called for escrowing the private key we just generated,
+//this function adds all the correct elements to the request.
+//That consists of adding CRMFEncryptedKey to the reques as part
+//of the CRMFPKIArchiveOptions Control.
+static nsresult
+nsSetEscrowAuthority(CRMFCertRequest *certReq, nsKeyPairInfo *keyInfo,
+                     nsNSSCertificate *wrappingCert)
+{
+  if (!wrappingCert ||
+      CRMF_CertRequestIsControlPresent(certReq, crmfPKIArchiveOptionsControl)){
+    return NS_ERROR_FAILURE;
+  }
+  ScopedCERTCertificate cert(wrappingCert->GetCert());
+  if (!cert)
+    return NS_ERROR_FAILURE;
+
+  CRMFEncryptedKey *encrKey = 
+      CRMF_CreateEncryptedKeyWithEncryptedValue(keyInfo->privKey, cert.get());
+  if (!encrKey)
+    return NS_ERROR_FAILURE;
+
+  CRMFPKIArchiveOptions *archOpt = 
+      CRMF_CreatePKIArchiveOptions(crmfEncryptedPrivateKey, encrKey);
+  if (!archOpt) {
+    CRMF_DestroyEncryptedKey(encrKey);
+    return NS_ERROR_FAILURE;
+  }
+  SECStatus srv = CRMF_CertRequestSetPKIArchiveOptions(certReq, archOpt);
+  CRMF_DestroyEncryptedKey(encrKey);
+  CRMF_DestroyPKIArchiveOptions(archOpt);
+  if (srv != SECSuccess)
+    return NS_ERROR_FAILURE;
+
+  return NS_OK;
+}
+
+//Set the Distinguished Name (Subject Name) for the cert
+//being requested.
+static nsresult
+nsSetDNForRequest(CRMFCertRequest *certReq, char *reqDN)
+{
+  if (!reqDN || CRMF_CertRequestIsFieldPresent(certReq, crmfSubject)) {
+    return NS_ERROR_FAILURE;
+  }
+  ScopedCERTName subjectName(CERT_AsciiToName(reqDN));
+  if (!subjectName) {
+    return NS_ERROR_FAILURE;
+  }
+  SECStatus srv = CRMF_CertRequestSetTemplateField(certReq, crmfSubject,
+                                                   static_cast<void*>
+                                                              (subjectName));
+  return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+//Set Registration Token Control on the request.
+static nsresult
+nsSetRegToken(CRMFCertRequest *certReq, char *regToken)
+{
+  // this should never happen, but might as well add this.
+  NS_ASSERTION(certReq, "A bogus certReq passed to nsSetRegToken");
+  if (regToken){
+    if (CRMF_CertRequestIsControlPresent(certReq, crmfRegTokenControl))
+      return NS_ERROR_FAILURE;
+  
+    SECItem src;
+    src.data = (unsigned char*)regToken;
+    src.len  = strlen(regToken);
+    SECItem *derEncoded = SEC_ASN1EncodeItem(nullptr, nullptr, &src, 
+                                        SEC_ASN1_GET(SEC_UTF8StringTemplate));
+
+    if (!derEncoded)
+      return NS_ERROR_FAILURE;
+
+    SECStatus srv = CRMF_CertRequestSetRegTokenControl(certReq, derEncoded);
+    SECITEM_FreeItem(derEncoded,true);
+    if (srv != SECSuccess)
+      return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+//Set the Authenticator control on the cert reuest.  It's just
+//a string that gets passed along.
+static nsresult
+nsSetAuthenticator(CRMFCertRequest *certReq, char *authenticator)
+{
+  //This should never happen, but might as well check.
+  NS_ASSERTION(certReq, "Bogus certReq passed to nsSetAuthenticator");
+  if (authenticator) {
+    if (CRMF_CertRequestIsControlPresent(certReq, crmfAuthenticatorControl))
+      return NS_ERROR_FAILURE;
+    
+    SECItem src;
+    src.data = (unsigned char*)authenticator;
+    src.len  = strlen(authenticator);
+    SECItem *derEncoded = SEC_ASN1EncodeItem(nullptr, nullptr, &src,
+                                     SEC_ASN1_GET(SEC_UTF8StringTemplate));
+    if (!derEncoded)
+      return NS_ERROR_FAILURE;
+
+    SECStatus srv = CRMF_CertRequestSetAuthenticatorControl(certReq, 
+                                                            derEncoded);
+    SECITEM_FreeItem(derEncoded, true);
+    if (srv != SECSuccess)
+      return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+// ASN1 DER encoding rules say that when encoding a BIT string,
+// the length in the header for the bit string is the number 
+// of "useful" bits in the BIT STRING.  So the function finds
+// it and sets accordingly for the returned item.
+static void
+nsPrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value)
+{
+  unsigned char onebyte;
+  unsigned int i, len = 0;
+
+  /* to prevent warning on some platform at compile time */
+  onebyte = '\0';
+  /* Get the position of the right-most turn-on bit */
+  for (i = 0; i < (value->len ) * 8; ++i) {
+    if (i % 8 == 0)
+      onebyte = value->data[i/8];
+    if (onebyte & 0x80)
+      len = i;
+    onebyte <<= 1;
+  }
+
+  bitsmap->data = value->data;
+  /* Add one here since we work with base 1 */
+  bitsmap->len = len + 1;
+}
+
+//This next section defines all the functions that sets the 
+//keyUsageExtension for all the different types of key gens
+//we handle.  The keyUsageExtension is just a bit flag extension
+//that we set in wrapper functions that call straight into
+//nsSetKeyUsageExtension.  There is one wrapper funciton for each
+//keyGenType.  The correct function will eventually be called 
+//by going through a switch statement based on the nsKeyGenType
+//in the nsKeyPairInfo struct.
+static nsresult
+nsSetKeyUsageExtension(CRMFCertRequest *crmfReq,
+                       unsigned char   keyUsage)
+{
+  SECItem                 *encodedExt= nullptr;
+  SECItem                  keyUsageValue = { (SECItemType) 0, nullptr, 0 };
+  SECItem                  bitsmap = { (SECItemType) 0, nullptr, 0 };
+  SECStatus                srv;
+  CRMFCertExtension       *ext = nullptr;
+  CRMFCertExtCreationInfo  extAddParams;
+  SEC_ASN1Template         bitStrTemplate = {SEC_ASN1_BIT_STRING, 0, nullptr,
+                                             sizeof(SECItem)};
+
+  keyUsageValue.data = &keyUsage;
+  keyUsageValue.len  = 1;
+  nsPrepareBitStringForEncoding(&bitsmap, &keyUsageValue);
+
+  encodedExt = SEC_ASN1EncodeItem(nullptr, nullptr, &bitsmap,&bitStrTemplate);
+  if (!encodedExt) {
+    goto loser;
+  }
+  ext = CRMF_CreateCertExtension(SEC_OID_X509_KEY_USAGE, true, encodedExt);
+  if (!ext) {
+      goto loser;
+  }
+  extAddParams.numExtensions = 1;
+  extAddParams.extensions = &ext;
+  srv = CRMF_CertRequestSetTemplateField(crmfReq, crmfExtension,
+                                         &extAddParams);
+  if (srv != SECSuccess) {
+      goto loser;
+  }
+  CRMF_DestroyCertExtension(ext);
+  SECITEM_FreeItem(encodedExt, true);
+  return NS_OK;
+ loser:
+  if (ext) {
+    CRMF_DestroyCertExtension(ext);
+  }
+  if (encodedExt) {
+      SECITEM_FreeItem(encodedExt, true);
+  }
+  return NS_ERROR_FAILURE;
+}
+
+static nsresult
+nsSetRSADualUse(CRMFCertRequest *crmfReq)
+{
+  unsigned char keyUsage =   KU_DIGITAL_SIGNATURE
+                           | KU_NON_REPUDIATION
+                           | KU_KEY_ENCIPHERMENT;
+
+  return nsSetKeyUsageExtension(crmfReq, keyUsage);
+}
+
+static nsresult
+nsSetRSAKeyEx(CRMFCertRequest *crmfReq)
+{
+  unsigned char keyUsage = KU_KEY_ENCIPHERMENT;
+
+  return nsSetKeyUsageExtension(crmfReq, keyUsage);
+}
+
+static nsresult
+nsSetRSASign(CRMFCertRequest *crmfReq)
+{
+  unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
+
+
+  return nsSetKeyUsageExtension(crmfReq, keyUsage);
+}
+
+static nsresult
+nsSetRSANonRepudiation(CRMFCertRequest *crmfReq)
+{
+  unsigned char keyUsage = KU_NON_REPUDIATION;
+
+  return nsSetKeyUsageExtension(crmfReq, keyUsage);
+}
+
+static nsresult
+nsSetRSASignNonRepudiation(CRMFCertRequest *crmfReq)
+{
+  unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
+                           KU_NON_REPUDIATION;
+
+  return nsSetKeyUsageExtension(crmfReq, keyUsage);
+}
+
+static nsresult
+nsSetECDualUse(CRMFCertRequest *crmfReq)
+{
+  unsigned char keyUsage =   KU_DIGITAL_SIGNATURE
+                           | KU_NON_REPUDIATION
+                           | KU_KEY_AGREEMENT;
+
+  return nsSetKeyUsageExtension(crmfReq, keyUsage);
+}
+
+static nsresult
+nsSetECKeyEx(CRMFCertRequest *crmfReq)
+{
+  unsigned char keyUsage = KU_KEY_AGREEMENT;
+
+  return nsSetKeyUsageExtension(crmfReq, keyUsage);
+}
+
+static nsresult
+nsSetECSign(CRMFCertRequest *crmfReq)
+{
+  unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
+
+
+  return nsSetKeyUsageExtension(crmfReq, keyUsage);
+}
+
+static nsresult
+nsSetECNonRepudiation(CRMFCertRequest *crmfReq)
+{
+  unsigned char keyUsage = KU_NON_REPUDIATION;
+
+  return nsSetKeyUsageExtension(crmfReq, keyUsage);
+}
+
+static nsresult
+nsSetECSignNonRepudiation(CRMFCertRequest *crmfReq)
+{
+  unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
+                           KU_NON_REPUDIATION;
+
+  return nsSetKeyUsageExtension(crmfReq, keyUsage);
+}
+
+static nsresult
+nsSetDH(CRMFCertRequest *crmfReq)
+{
+  unsigned char keyUsage = KU_KEY_AGREEMENT;
+
+  return nsSetKeyUsageExtension(crmfReq, keyUsage);
+}
+
+static nsresult
+nsSetDSASign(CRMFCertRequest *crmfReq)
+{
+  unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
+
+  return nsSetKeyUsageExtension(crmfReq, keyUsage);
+}
+
+static nsresult
+nsSetDSANonRepudiation(CRMFCertRequest *crmfReq)
+{
+  unsigned char keyUsage = KU_NON_REPUDIATION;
+
+  return nsSetKeyUsageExtension(crmfReq, keyUsage);
+}
+
+static nsresult
+nsSetDSASignNonRepudiation(CRMFCertRequest *crmfReq)
+{
+  unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
+                           KU_NON_REPUDIATION;
+
+  return nsSetKeyUsageExtension(crmfReq, keyUsage);
+}
+
+static nsresult
+nsSetKeyUsageExtension(CRMFCertRequest *crmfReq, nsKeyGenType keyGenType)
+{
+  nsresult rv;
+
+  switch (keyGenType) {
+  case rsaDualUse:
+    rv = nsSetRSADualUse(crmfReq);
+    break;
+  case rsaEnc:
+    rv = nsSetRSAKeyEx(crmfReq);
+    break;
+  case rsaSign:
+    rv = nsSetRSASign(crmfReq);
+    break;
+  case rsaNonrepudiation:
+    rv = nsSetRSANonRepudiation(crmfReq);
+    break;
+  case rsaSignNonrepudiation:
+    rv = nsSetRSASignNonRepudiation(crmfReq);
+    break;
+  case ecDualUse:
+    rv = nsSetECDualUse(crmfReq);
+    break;
+  case ecEnc:
+    rv = nsSetECKeyEx(crmfReq);
+    break;
+  case ecSign:
+    rv = nsSetECSign(crmfReq);
+    break;
+  case ecNonrepudiation:
+    rv = nsSetECNonRepudiation(crmfReq);
+    break;
+  case ecSignNonrepudiation:
+    rv = nsSetECSignNonRepudiation(crmfReq);
+    break;
+  case dhEx:
+    rv = nsSetDH(crmfReq);
+    break;
+  case dsaSign:
+    rv = nsSetDSASign(crmfReq);
+    break;
+  case dsaNonrepudiation:
+    rv = nsSetDSANonRepudiation(crmfReq);
+    break;
+  case dsaSignNonrepudiation:
+    rv = nsSetDSASignNonRepudiation(crmfReq);
+    break;
+  default:
+    rv = NS_ERROR_FAILURE;
+    break;
+  }
+  return rv;
+}
+
+//Create a single CRMFCertRequest with all of the necessary parts 
+//already installed.  The request returned by this function will
+//have all the parts necessary and can just be added to a 
+//Certificate Request Message.
+static CRMFCertRequest*
+nsCreateSingleCertReq(nsKeyPairInfo *keyInfo, char *reqDN, char *regToken, 
+                      char *authenticator, nsNSSCertificate *wrappingCert)
+{
+  uint32_t reqID;
+  nsresult rv;
+
+  //The draft says the ID of the request should be a random
+  //number.  We don't have a way of tracking this number
+  //to compare when the reply actually comes back,though.
+  PK11_GenerateRandom((unsigned char*)&reqID, sizeof(reqID));
+  CRMFCertRequest *certReq = CRMF_CreateCertRequest(reqID);
+  if (!certReq)
+    return nullptr;
+
+  long version = SEC_CERTIFICATE_VERSION_3;
+  SECStatus srv;
+  CERTSubjectPublicKeyInfo *spki = nullptr;
+  srv = CRMF_CertRequestSetTemplateField(certReq, crmfVersion, &version);
+  if (srv != SECSuccess)
+    goto loser;
+  
+  spki = SECKEY_CreateSubjectPublicKeyInfo(keyInfo->pubKey);
+  if (!spki)
+    goto loser;
+
+  srv = CRMF_CertRequestSetTemplateField(certReq, crmfPublicKey, spki);
+  SECKEY_DestroySubjectPublicKeyInfo(spki);
+  if (srv != SECSuccess)
+    goto loser;
+
+  if (wrappingCert && ns_can_escrow(keyInfo->keyGenType)) {
+    rv = nsSetEscrowAuthority(certReq, keyInfo, wrappingCert);
+    if (NS_FAILED(rv))
+      goto loser;
+  }
+  rv = nsSetDNForRequest(certReq, reqDN);
+  if (NS_FAILED(rv))
+    goto loser;
+
+  rv = nsSetRegToken(certReq, regToken);
+  if (NS_FAILED(rv))
+    goto loser;
+
+  rv = nsSetAuthenticator(certReq, authenticator);
+  if (NS_FAILED(rv))
+    goto loser;
+
+ rv = nsSetKeyUsageExtension(certReq, keyInfo->keyGenType); 
+  if (NS_FAILED(rv))
+    goto loser;
+
+  return certReq;
+loser:
+  if (certReq) {
+    CRMF_DestroyCertRequest(certReq);
+  }
+  return nullptr;
+}
+
+/*
+ * This function will set the Proof Of Possession (POP) for a request
+ * associated with a key pair intended to do Key Encipherment.  Currently
+ * this means encryption only keys.
+ */
+static nsresult
+nsSetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg, bool isEscrowed)
+{
+  SECItem       bitString;
+  unsigned char der[2];
+  SECStatus     srv;
+
+  if (isEscrowed) {
+    /* For proof of possession on escrowed keys, we use the
+     * this Message option of POPOPrivKey and include a zero
+     * length bit string in the POP field.  This is OK because the encrypted
+     * private key already exists as part of the PKIArchiveOptions
+     * Control and that for all intents and purposes proves that
+     * we do own the private key.
+     */
+    der[0] = 0x03; /*We've got a bit string          */
+    der[1] = 0x00; /*We've got a 0 length bit string */
+    bitString.data = der;
+    bitString.len  = 2;
+    srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg, crmfThisMessage,
+                                              crmfNoSubseqMess, &bitString);
+  } else {
+    /* If the encryption key is not being escrowed, then we set the 
+     * Proof Of Possession to be a Challenge Response mechanism.
+     */
+    srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg,
+                                              crmfSubsequentMessage,
+                                              crmfChallengeResp, nullptr);
+  }
+  return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+static void
+nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len);
+
+static void
+nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len);
+
+static nsresult
+nsSet_EC_DHMAC_ProofOfPossession(CRMFCertReqMsg *certReqMsg, 
+                                 nsKeyPairInfo  *keyInfo,
+                                 CRMFCertRequest *certReq)
+{
+  // RFC 2511 Appendix A section 2 a) defines,
+  // the "text" input for HMAC shall be the DER encoded version of
+  // of the single cert request.
+  // We'll produce that encoding and destroy it afterwards,
+  // because when sending the complete package to the CA,
+  // we'll use a different encoding, one that includes POP and
+  // allows multiple requests to be sent in one step.
+
+  unsigned long der_request_len = 0;
+  ScopedSECItem der_request;
+
+  if (SECSuccess != CRMF_EncodeCertRequest(certReq, 
+                                           nsCRMFEncoderItemCount, 
+                                           &der_request_len))
+    return NS_ERROR_FAILURE;
+
+  der_request = SECITEM_AllocItem(nullptr, nullptr, der_request_len);
+  if (!der_request)
+    return NS_ERROR_FAILURE;
+
+  // set len in returned SECItem back to zero, because it will
+  // be used as the destination offset inside the 
+  // nsCRMFEncoderItemStore callback.
+
+  der_request->len = 0;
+
+  if (SECSuccess != CRMF_EncodeCertRequest(certReq, 
+                                           nsCRMFEncoderItemStore, 
+                                           der_request))
+    return NS_ERROR_FAILURE;
+
+  // RFC 2511 Appendix A section 2 c):
+  // "A key K is derived from the shared secret Kec and the subject and
+  //  issuer names in the CA's certificate as follows:
+  //  K = SHA1(DER-encoded-subjectName | Kec | DER-encoded-issuerName)"
+
+  ScopedPK11SymKey shared_secret;
+  ScopedPK11SymKey subject_and_secret;
+  ScopedPK11SymKey subject_and_secret_and_issuer;
+  ScopedPK11SymKey sha1_of_subject_and_secret_and_issuer;
+
+  shared_secret = 
+    PK11_PubDeriveWithKDF(keyInfo->privKey, // SECKEYPrivateKey *privKey
+                          keyInfo->ecPopPubKey,  // SECKEYPublicKey *pubKey
+                          false, // bool isSender
+                          nullptr, // SECItem *randomA
+                          nullptr, // SECItem *randomB
+                          CKM_ECDH1_DERIVE, // CK_MECHANISM_TYPE derive
+                          CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE target
+                          CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
+                          0, // int keySize
+                          CKD_NULL, // CK_ULONG kdf
+                          nullptr, // SECItem *sharedData
+                          nullptr); // void *wincx
+
+  if (!shared_secret)
+    return NS_ERROR_FAILURE;
+
+  CK_KEY_DERIVATION_STRING_DATA concat_data_base;
+  concat_data_base.pData = keyInfo->ecPopCert->derSubject.data;
+  concat_data_base.ulLen = keyInfo->ecPopCert->derSubject.len;
+  SECItem concat_data_base_item;
+  concat_data_base_item.data = (unsigned char*)&concat_data_base;
+  concat_data_base_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
+
+  subject_and_secret =
+    PK11_Derive(shared_secret, // PK11SymKey *baseKey
+                CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE mechanism
+                &concat_data_base_item, // SECItem *param
+                CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE target
+                CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
+                0); // int keySize
+
+  if (!subject_and_secret)
+    return NS_ERROR_FAILURE;
+
+  CK_KEY_DERIVATION_STRING_DATA concat_base_data;
+  concat_base_data.pData = keyInfo->ecPopCert->derSubject.data;
+  concat_base_data.ulLen = keyInfo->ecPopCert->derSubject.len;
+  SECItem concat_base_data_item;
+  concat_base_data_item.data = (unsigned char*)&concat_base_data;
+  concat_base_data_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
+
+  subject_and_secret_and_issuer =
+    PK11_Derive(subject_and_secret, // PK11SymKey *baseKey
+                CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE mechanism
+                &concat_base_data_item, // SECItem *param
+                CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE target
+                CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
+                0); // int keySize
+
+  if (!subject_and_secret_and_issuer)
+    return NS_ERROR_FAILURE;
+
+  sha1_of_subject_and_secret_and_issuer =
+    PK11_Derive(subject_and_secret_and_issuer, // PK11SymKey *baseKey
+                CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE mechanism
+                nullptr, // SECItem *param
+                CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE target
+                CKA_SIGN, // CK_ATTRIBUTE_TYPE operation
+                0); // int keySize
+
+  if (!sha1_of_subject_and_secret_and_issuer)
+    return NS_ERROR_FAILURE;
+
+  PK11Context *context = nullptr;
+  PK11ContextCleanerTrueParam context_cleaner(context);
+
+  SECItem ignore;
+  ignore.data = 0;
+  ignore.len = 0;
+
+  context = 
+    PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE type
+                               CKA_SIGN, // CK_ATTRIBUTE_TYPE operation
+                               sha1_of_subject_and_secret_and_issuer, // PK11SymKey *symKey
+                               &ignore); // SECItem *param
+
+  if (!context)
+    return NS_ERROR_FAILURE;
+
+  if (SECSuccess != PK11_DigestBegin(context))
+    return NS_ERROR_FAILURE;
+
+  if (SECSuccess != 
+      PK11_DigestOp(context, der_request->data, der_request->len))
+    return NS_ERROR_FAILURE;
+
+  ScopedAutoSECItem result_hmac_sha1_item(SHA1_LENGTH);
+
+  if (SECSuccess !=
+      PK11_DigestFinal(context, 
+                       result_hmac_sha1_item.data, 
+                       &result_hmac_sha1_item.len, 
+                       SHA1_LENGTH))
+    return NS_ERROR_FAILURE;
+
+  if (SECSuccess !=
+      CRMF_CertReqMsgSetKeyAgreementPOP(certReqMsg, crmfDHMAC,
+                                        crmfNoSubseqMess, &result_hmac_sha1_item))
+    return NS_ERROR_FAILURE;
+
+  return NS_OK;
+}
+
+static nsresult
+nsSetProofOfPossession(CRMFCertReqMsg *certReqMsg, 
+                       nsKeyPairInfo  *keyInfo,
+                       CRMFCertRequest *certReq)
+{
+  // Depending on the type of cert request we'll try
+  // POP mechanisms in different order,
+  // and add the result to the cert request message.
+  //
+  // For any signing or dual use cert,
+  //   try signing first,
+  //   fall back to DHMAC if we can
+  //     (EC cert requests that provide keygen param "popcert"),
+  //   otherwise fail.
+  //
+  // For encryption only certs that get escrowed, this is sufficient.
+  //
+  // For encryption only certs, that are not being escrowed, 
+  //   try DHMAC if we can 
+  //     (EC cert requests that provide keygen param "popcert"),
+  //   otherwise we'll indicate challenge response should be used.
+  
+  bool isEncryptionOnlyCertRequest = false;
+  bool escrowEncryptionOnlyCert = false;
+  
+  switch (keyInfo->keyGenType)
+  {
+    case rsaEnc:
+    case ecEnc:
+      isEncryptionOnlyCertRequest = true;
+      break;
+    
+    case rsaSign:
+    case rsaDualUse:
+    case rsaNonrepudiation:
+    case rsaSignNonrepudiation:
+    case ecSign:
+    case ecDualUse:
+    case ecNonrepudiation:
+    case ecSignNonrepudiation:
+    case dsaSign:
+    case dsaNonrepudiation:
+    case dsaSignNonrepudiation:
+      break;
+    
+    case dhEx:
+    /* This case may be supported in the future, but for now, we just fall 
+      * though to the default case and return an error for diffie-hellman keys.
+    */
+    default:
+      return NS_ERROR_FAILURE;
+  };
+    
+  if (isEncryptionOnlyCertRequest)
+  {
+    escrowEncryptionOnlyCert = 
+      CRMF_CertRequestIsControlPresent(certReq,crmfPKIArchiveOptionsControl);
+  }
+    
+  bool gotDHMACParameters = false;
+  
+  if (isECKeyGenType(keyInfo->keyGenType) && 
+      keyInfo->ecPopCert && 
+      keyInfo->ecPopPubKey)
+  {
+    gotDHMACParameters = true;
+  }
+  
+  if (isEncryptionOnlyCertRequest)
+  {
+    if (escrowEncryptionOnlyCert)
+      return nsSetKeyEnciphermentPOP(certReqMsg, true); // escrowed
+    
+    if (gotDHMACParameters)
+      return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq);
+    
+    return nsSetKeyEnciphermentPOP(certReqMsg, false); // not escrowed
+  }
+  
+  // !isEncryptionOnlyCertRequest
+  
+  SECStatus srv = CRMF_CertReqMsgSetSignaturePOP(certReqMsg,
+                                                 keyInfo->privKey,
+                                                 keyInfo->pubKey, nullptr,
+                                                 nullptr, nullptr);
+
+  if (srv == SECSuccess)
+    return NS_OK;
+  
+  if (!gotDHMACParameters)
+    return NS_ERROR_FAILURE;
+  
+  return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq);
+}
+
+static void
+nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len)
+{
+  unsigned long *count = (unsigned long *)arg;
+  *count += len;
+}
+
+static void
+nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len)
+{
+  SECItem *dest = (SECItem *)arg;
+  memcpy(dest->data + dest->len, buf, len);
+  dest->len += len;
+}
+
+static SECItem*
+nsEncodeCertReqMessages(CRMFCertReqMsg **certReqMsgs)
+{
+  unsigned long len = 0;
+  if (CRMF_EncodeCertReqMessages(certReqMsgs, nsCRMFEncoderItemCount, &len)
+      != SECSuccess) {
+    return nullptr;
+  }
+  SECItem *dest = (SECItem *)PORT_Alloc(sizeof(SECItem));
+  if (!dest) {
+    return nullptr;
+  }
+  dest->type = siBuffer;
+  dest->data = (unsigned char *)PORT_Alloc(len);
+  if (!dest->data) {
+    PORT_Free(dest);
+    return nullptr;
+  }
+  dest->len = 0;
+
+  if (CRMF_EncodeCertReqMessages(certReqMsgs, nsCRMFEncoderItemStore, dest)
+      != SECSuccess) {
+    SECITEM_FreeItem(dest, true);
+    return nullptr;
+  }
+  return dest;
+}
+
+//Create a Base64 encoded CRMFCertReqMsg that can be sent to a CA
+//requesting one or more certificates to be issued.  This function
+//creates a single cert request per key pair and then appends it to
+//a message that is ultimately sent off to a CA.
+static char*
+nsCreateReqFromKeyPairs(nsKeyPairInfo *keyids, int32_t numRequests,
+                        char *reqDN, char *regToken, char *authenticator,
+                        nsNSSCertificate *wrappingCert) 
+{
+  // We'use the goto notation for clean-up purposes in this function
+  // that calls the C API of NSS.
+  int32_t i;
+  // The ASN1 encoder in NSS wants the last entry in the array to be
+  // nullptr so that it knows when the last element is.
+  CRMFCertReqMsg **certReqMsgs = new CRMFCertReqMsg*[numRequests+1];
+  CRMFCertRequest *certReq;
+  if (!certReqMsgs)
+    return nullptr;
+  memset(certReqMsgs, 0, sizeof(CRMFCertReqMsg*)*(1+numRequests));
+  SECStatus srv;
+  nsresult rv;
+  SECItem *encodedReq;
+  char *retString;
+  for (i=0; i<numRequests; i++) {
+    certReq = nsCreateSingleCertReq(&keyids[i], reqDN, regToken, authenticator,
+                                    wrappingCert);
+    if (!certReq)
+      goto loser;
+
+    certReqMsgs[i] = CRMF_CreateCertReqMsg();
+    if (!certReqMsgs[i])
+      goto loser;
+    srv = CRMF_CertReqMsgSetCertRequest(certReqMsgs[i], certReq);
+    if (srv != SECSuccess)
+      goto loser;
+
+    rv = nsSetProofOfPossession(certReqMsgs[i], &keyids[i], certReq);
+    if (NS_FAILED(rv))
+      goto loser;
+    CRMF_DestroyCertRequest(certReq);
+  }
+  encodedReq = nsEncodeCertReqMessages(certReqMsgs);
+  nsFreeCertReqMessages(certReqMsgs, numRequests);
+
+  retString = NSSBase64_EncodeItem (nullptr, nullptr, 0, encodedReq);
+  SECITEM_FreeItem(encodedReq, true);
+  return retString;
+loser:
+  nsFreeCertReqMessages(certReqMsgs,numRequests);
+  return nullptr;
+}
+
+//The top level method which is a member of nsIDOMCrypto
+//for generate a base64 encoded CRMF request.
+CRMFObject*
+nsCrypto::GenerateCRMFRequest(JSContext* aContext,
+                              const nsCString& aReqDN,
+                              const nsCString& aRegToken,
+                              const nsCString& aAuthenticator,
+                              const nsCString& aEaCert,
+                              const nsCString& aJsCallback,
+                              const Sequence<JS::Value>& aArgs,
+                              ErrorResult& aRv)
+{
+  nsNSSShutDownPreventionLock locker;
+  nsresult nrv;
+
+  uint32_t argc = aArgs.Length();
+
+  /*
+   * Get all of the parameters.
+   */
+  if (argc % 3 != 0) {
+    aRv.ThrowNotEnoughArgsError();
+    return nullptr;
+  }
+
+  if (aReqDN.IsVoid()) {
+    NS_WARNING("no DN specified");
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  if (aJsCallback.IsVoid()) {
+    NS_WARNING("no completion function specified");
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(GetParentObject());
+  if (MOZ_UNLIKELY(!globalObject)) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIContentSecurityPolicy> csp;
+  if (!nsContentUtils::GetContentSecurityPolicy(getter_AddRefs(csp))) {
+    NS_ERROR("Error: failed to get CSP");
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  bool evalAllowed = true;
+  bool reportEvalViolations = false;
+  if (csp && NS_FAILED(csp->GetAllowsEval(&reportEvalViolations, &evalAllowed))) {
+    NS_WARNING("CSP: failed to get allowsEval");
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  if (reportEvalViolations) {
+    NS_NAMED_LITERAL_STRING(scriptSample, "window.crypto.generateCRMFRequest: call to eval() or related function blocked by CSP");
+
+    const char *fileName;
+    uint32_t lineNum;
+    nsJSUtils::GetCallingLocation(aContext, &fileName, &lineNum);
+    csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
+                             NS_ConvertASCIItoUTF16(fileName),
+                             scriptSample,
+                             lineNum,
+                             EmptyString(),
+                             EmptyString());
+  }
+
+  if (!evalAllowed) {
+    NS_WARNING("eval() not allowed by Content Security Policy");
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  //Put up some UI warning that someone is trying to
+  //escrow the private key.
+  //Don't addref this copy.  That way ths reference goes away
+  //at the same the nsIX09Cert ref goes away.
+  nsNSSCertificate *escrowCert = nullptr;
+  nsCOMPtr<nsIX509Cert> nssCert;
+  bool willEscrow = false;
+  if (!aEaCert.IsVoid()) {
+    SECItem certDer = {siBuffer, nullptr, 0};
+    SECStatus srv = ATOB_ConvertAsciiToItem(&certDer, aEaCert.get());
+    if (srv != SECSuccess) {
+      aRv.Throw(NS_ERROR_FAILURE);
+      return nullptr;
+    }
+    ScopedCERTCertificate cert(
+      CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
+                              &certDer, nullptr, false, true));
+    if (!cert) {
+      aRv.Throw(NS_ERROR_FAILURE);
+      return nullptr;
+    }
+
+    escrowCert = nsNSSCertificate::Create(cert.get());
+    nssCert = escrowCert;
+    if (!nssCert) {
+      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+      return nullptr;
+    }
+
+    nsCOMPtr<nsIDOMCryptoDialogs> dialogs;
+    nsresult rv = getNSSDialogs(getter_AddRefs(dialogs),
+                                NS_GET_IID(nsIDOMCryptoDialogs),
+                                NS_DOMCRYPTODIALOGS_CONTRACTID);
+    if (NS_FAILED(rv)) {
+      aRv.Throw(rv);
+      return nullptr;
+    }
+
+    bool okay=false;
+    {
+      nsPSMUITracker tracker;
+      if (tracker.isUIForbidden()) {
+        okay = false;
+      }
+      else {
+        dialogs->ConfirmKeyEscrow(nssCert, &okay);
+      }
+    }
+    if (!okay) {
+      aRv.Throw(NS_ERROR_FAILURE);
+      return nullptr;
+    }
+    willEscrow = true;
+  }
+  nsCOMPtr<nsIInterfaceRequestor> uiCxt = new PipUIContext;
+  int32_t numRequests = argc / 3;
+  nsKeyPairInfo *keyids = new nsKeyPairInfo[numRequests];
+  memset(keyids, 0, sizeof(nsKeyPairInfo)*numRequests);
+  int keyInfoIndex;
+  uint32_t i;
+  PK11SlotInfo *slot = nullptr;
+  // Go through all of the arguments and generate the appropriate key pairs.
+  for (i=0,keyInfoIndex=0; i<argc; i+=3,keyInfoIndex++) {
+    nrv = cryptojs_ReadArgsAndGenerateKey(aContext,
+                                          const_cast<JS::Value*>(&aArgs[i]),
+                                          &keyids[keyInfoIndex],
+                                          uiCxt, &slot, willEscrow);
+
+    if (NS_FAILED(nrv)) {
+      if (slot)
+        PK11_FreeSlot(slot);
+      nsFreeKeyPairInfo(keyids,numRequests);
+      aRv.Throw(nrv);
+      return nullptr;
+    }
+  }
+  // By this time we'd better have a slot for the key gen.
+  NS_ASSERTION(slot, "There was no slot selected for key generation");
+  if (slot)
+    PK11_FreeSlot(slot);
+
+  char *encodedRequest = nsCreateReqFromKeyPairs(keyids,numRequests,
+                                                 const_cast<char*>(aReqDN.get()),
+                                                 const_cast<char*>(aRegToken.get()),
+                                                 const_cast<char*>(aAuthenticator.get()),
+                                                 escrowCert);
+  if (!encodedRequest) {
+    nsFreeKeyPairInfo(keyids, numRequests);
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  CRMFObject* newObject = new CRMFObject();
+  newObject->SetCRMFRequest(encodedRequest);
+  PORT_Free(encodedRequest);
+  nsFreeKeyPairInfo(keyids, numRequests);
+
+  // Post an event on the UI queue so that the JS gets called after
+  // we return control to the JS layer.  Why do we have to this?
+  // Because when this API was implemented for PSM 1.x w/ Communicator,
+  // the only way to make this method work was to have a callback
+  // in the JS layer that got called after key generation had happened.
+  // So for backwards compatibility, we return control and then just post
+  // an event to call the JS the script provides as the code to execute
+  // when the request has been generated.
+  //
+
+  MOZ_ASSERT(nsContentUtils::GetCurrentJSContext());
+  nsCryptoRunArgs *args = new nsCryptoRunArgs();
+
+  args->m_globalObject = globalObject;
+  if (!aJsCallback.IsVoid()) {
+    args->m_jsCallback = aJsCallback;
+  }
+
+  nsRefPtr<nsCryptoRunnable> cryptoRunnable(new nsCryptoRunnable(args));
+
+  nsresult rv = NS_DispatchToMainThread(cryptoRunnable);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
+
+  return newObject;
+}
+
+// Reminder that we inherit the memory passed into us here.
+// An implementation to let us back up certs as an event.
+nsP12Runnable::nsP12Runnable(nsIX509Cert **certArr, int32_t numCerts,
+                             nsIPK11Token *token)
+{
+  mCertArr  = certArr;
+  mNumCerts = numCerts;
+  mToken = token;
+}
+
+nsP12Runnable::~nsP12Runnable()
+{
+  int32_t i;
+  for (i=0; i<mNumCerts; i++) {
+      NS_IF_RELEASE(mCertArr[i]);
+  }
+  delete []mCertArr;
+}
+
+
+//Implementation that backs cert(s) into a PKCS12 file
+NS_IMETHODIMP
+nsP12Runnable::Run()
+{
+  NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
+
+  NS_ASSERTION(NS_IsMainThread(), "nsP12Runnable dispatched to the wrong thread");
+
+  nsNSSShutDownPreventionLock locker;
+  NS_ASSERTION(mCertArr, "certArr is NULL while trying to back up");
+
+  nsString final;
+  nsString temp;
+  nsresult rv;
+
+  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
+  if (NS_FAILED(rv))
+    return rv;
+
+  //Build up the message that let's the user know we're trying to 
+  //make PKCS12 backups of the new certs.
+  nssComponent->GetPIPNSSBundleString("ForcedBackup1", final);
+  final.Append(MOZ_UTF16("\n\n"));
+  nssComponent->GetPIPNSSBundleString("ForcedBackup2", temp);
+  final.Append(temp.get());
+  final.Append(MOZ_UTF16("\n\n"));
+
+  nssComponent->GetPIPNSSBundleString("ForcedBackup3", temp);
+
+  final.Append(temp.get());
+  nsNSSComponent::ShowAlertWithConstructedString(final);
+
+  nsCOMPtr<nsIFilePicker> filePicker = 
+                        do_CreateInstance("@mozilla.org/filepicker;1", &rv);
+  if (!filePicker) {
+    NS_ERROR("Could not create a file picker when backing up certs.");
+    return rv;
+  }
+
+  nsCOMPtr<nsIWindowWatcher> wwatch =
+    (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIDOMWindow> window;
+  wwatch->GetActiveWindow(getter_AddRefs(window));
+
+  nsString filePickMessage;
+  nssComponent->GetPIPNSSBundleString("chooseP12BackupFileDialog",
+                                      filePickMessage);
+  rv = filePicker->Init(window, filePickMessage, nsIFilePicker::modeSave);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  filePicker->AppendFilter(NS_LITERAL_STRING("PKCS12"),
+                           NS_LITERAL_STRING("*.p12"));
+  filePicker->AppendFilters(nsIFilePicker::filterAll);
+
+  int16_t dialogReturn;
+  filePicker->Show(&dialogReturn);
+  if (dialogReturn == nsIFilePicker::returnCancel)
+    return NS_OK;  //User canceled.  It'd be nice if they couldn't, 
+                   //but oh well.
+
+  nsCOMPtr<nsIFile> localFile;
+  rv = filePicker->GetFile(getter_AddRefs(localFile));
+  if (NS_FAILED(rv))
+    return NS_ERROR_FAILURE;
+
+  nsPKCS12Blob p12Cxt;
+  
+  p12Cxt.SetToken(mToken);
+  p12Cxt.ExportToFile(localFile, mCertArr, mNumCerts);
+  return NS_OK;
+}
+
+nsCryptoRunArgs::nsCryptoRunArgs() {}
+
+nsCryptoRunArgs::~nsCryptoRunArgs() {}
+
+nsCryptoRunnable::nsCryptoRunnable(nsCryptoRunArgs *args)
+{
+  nsNSSShutDownPreventionLock locker;
+  NS_ASSERTION(args,"Passed nullptr to nsCryptoRunnable constructor.");
+  m_args = args;
+  NS_IF_ADDREF(m_args);
+}
+
+nsCryptoRunnable::~nsCryptoRunnable()
+{
+  nsNSSShutDownPreventionLock locker;
+  NS_IF_RELEASE(m_args);
+}
+
+//Implementation that runs the callback passed to 
+//crypto.generateCRMFRequest as an event.
+NS_IMETHODIMP
+nsCryptoRunnable::Run()
+{
+  nsNSSShutDownPreventionLock locker;
+
+  // We're going to run script via JS_EvaluateScript, so we need an
+  // AutoEntryScript. This is Gecko specific and not on a standards track.
+  AutoEntryScript aes(m_args->m_globalObject);
+  JSContext* cx = aes.cx();
+  JS::RootedObject scope(cx, JS::CurrentGlobalOrNull(cx));
+
+  bool ok =
+    JS_EvaluateScript(cx, scope, m_args->m_jsCallback,
+                      strlen(m_args->m_jsCallback), nullptr, 0);
+  return ok ? NS_OK : NS_ERROR_FAILURE;
+}
+
+//Quick helper function to check if a newly issued cert
+//already exists in the user's database.
+static bool
+nsCertAlreadyExists(SECItem *derCert)
+{
+  CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
+  bool retVal = false;
+
+  ScopedCERTCertificate cert(CERT_FindCertByDERCert(handle, derCert));
+  if (cert) {
+    if (cert->isperm && !cert->nickname && !cert->emailAddr) {
+      //If the cert doesn't have a nickname or email addr, it is
+      //bogus cruft, so delete it.
+      SEC_DeletePermCertificate(cert.get());
+    } else if (cert->isperm) {
+      retVal = true;
+    }
+  }
+  return retVal;
+}
+
+static int32_t
+nsCertListCount(CERTCertList *certList)
+{
+  int32_t numCerts = 0;
+  CERTCertListNode *node;
+
+  node = CERT_LIST_HEAD(certList);
+  while (!CERT_LIST_END(node, certList)) {
+    numCerts++;
+    node = CERT_LIST_NEXT(node);
+  }
+  return numCerts;
+}
+
+//Import user certificates that arrive as a CMMF base64 encoded
+//string.
+void
+nsCrypto::ImportUserCertificates(const nsAString& aNickname,
+                                 const nsAString& aCmmfResponse,
+                                 bool aDoForcedBackup,
+                                 nsAString& aReturn,
+                                 ErrorResult& aRv)
+{
+  nsNSSShutDownPreventionLock locker;
+  char *nickname=nullptr, *cmmfResponse=nullptr;
+  CMMFCertRepContent *certRepContent = nullptr;
+  int numResponses = 0;
+  nsIX509Cert **certArr = nullptr;
+  int i;
+  CMMFCertResponse *currResponse;
+  CMMFPKIStatus reqStatus;
+  CERTCertificate *currCert;
+  PK11SlotInfo *slot;
+  nsAutoCString localNick;
+  nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
+  nsresult rv = NS_OK;
+  nsCOMPtr<nsIPK11Token> token;
+
+  nickname = ToNewCString(aNickname);
+  cmmfResponse = ToNewCString(aCmmfResponse);
+  if (nsCRT::strcmp("null", nickname) == 0) {
+    nsMemory::Free(nickname);
+    nickname = nullptr;
+  }
+
+  SECItem cmmfDer = {siBuffer, nullptr, 0};
+  SECStatus srv = ATOB_ConvertAsciiToItem(&cmmfDer, cmmfResponse);
+
+  if (srv != SECSuccess) {
+    rv = NS_ERROR_FAILURE;
+    goto loser;
+  }
+
+  certRepContent = CMMF_CreateCertRepContentFromDER(CERT_GetDefaultCertDB(),
+                                                    (const char*)cmmfDer.data,
+                                                    cmmfDer.len);
+  if (!certRepContent) {
+    rv = NS_ERROR_FAILURE;
+    goto loser;
+  }
+
+  numResponses = CMMF_CertRepContentGetNumResponses(certRepContent);
+
+  if (aDoForcedBackup) {
+    //We've been asked to force the user to back up these
+    //certificates.  Let's keep an array of them around which
+    //we pass along to the nsP12Runnable to use.
+    certArr = new nsIX509Cert*[numResponses];
+    // If this is nullptr, chances are we're gonna fail really
+    // soon, but let's try to keep going just in case.
+    if (!certArr)
+      aDoForcedBackup = false;
+
+    memset(certArr, 0, sizeof(nsIX509Cert*)*numResponses);
+  }
+  for (i=0; i<numResponses; i++) {
+    currResponse = CMMF_CertRepContentGetResponseAtIndex(certRepContent,i);
+    if (!currResponse) {
+      rv = NS_ERROR_FAILURE;
+      goto loser;
+    }
+    reqStatus = CMMF_CertResponseGetPKIStatusInfoStatus(currResponse);
+    if (!(reqStatus == cmmfGranted || reqStatus == cmmfGrantedWithMods)) {
+      // The CA didn't give us the cert we requested.
+      rv = NS_ERROR_FAILURE;
+      goto loser;
+    }
+    currCert = CMMF_CertResponseGetCertificate(currResponse, 
+                                               CERT_GetDefaultCertDB());
+    if (!currCert) {
+      rv = NS_ERROR_FAILURE;
+      goto loser;
+    }
+
+    if (nsCertAlreadyExists(&currCert->derCert)) {
+      if (aDoForcedBackup) {
+        certArr[i] = nsNSSCertificate::Create(currCert);
+        if (!certArr[i])
+          goto loser;
+        NS_ADDREF(certArr[i]);
+      }
+      CERT_DestroyCertificate(currCert);
+      CMMF_DestroyCertResponse(currResponse);
+      continue;
+    }
+    // Let's figure out which nickname to give the cert.  If 
+    // a certificate with the same subject name already exists,
+    // then just use that one, otherwise, get the default nickname.
+    if (currCert->nickname) {
+      localNick = currCert->nickname;
+    }
+    else if (!nickname || nickname[0] == '\0') {
+      nsNSSCertificateDB::get_default_nickname(currCert, ctx, localNick, locker);
+    } else {
+      //This is the case where we're getting a brand new
+      //cert that doesn't have the same subjectName as a cert
+      //that already exists in our db and the CA page has 
+      //designated a nickname to use for the newly issued cert.
+      localNick = nickname;
+    }
+    {
+      char *cast_const_away = const_cast<char*>(localNick.get());
+      slot = PK11_ImportCertForKey(currCert, cast_const_away, ctx);
+    }
+    if (!slot) {
+      rv = NS_ERROR_FAILURE;
+      goto loser;
+    }
+    if (aDoForcedBackup) {
+      certArr[i] = nsNSSCertificate::Create(currCert);
+      if (!certArr[i])
+        goto loser;
+      NS_ADDREF(certArr[i]);
+    }
+    CERT_DestroyCertificate(currCert);
+
+    if (!token)
+      token = new nsPK11Token(slot);
+
+    PK11_FreeSlot(slot);
+    CMMF_DestroyCertResponse(currResponse);
+  }
+  //Let the loser: label take care of freeing up our reference to
+  //nickname (This way we don't free it twice and avoid crashing.
+  //That would be a good thing.
+
+  //Import the root chain into the cert db.
+ {
+  ScopedCERTCertList caPubs(CMMF_CertRepContentGetCAPubs(certRepContent));
+  if (caPubs) {
+    int32_t numCAs = nsCertListCount(caPubs.get());
+    
+    NS_ASSERTION(numCAs > 0, "Invalid number of CA's");
+    if (numCAs > 0) {
+      CERTCertListNode *node;
+      SECItem *derCerts;
+
+      derCerts = static_cast<SECItem*>
+                            (nsMemory::Alloc(sizeof(SECItem)*numCAs));
+      if (!derCerts) {
+        rv = NS_ERROR_OUT_OF_MEMORY;
+        goto loser;
+      }
+      for (node = CERT_LIST_HEAD(caPubs), i=0; 
+           !CERT_LIST_END(node, caPubs);
+           node = CERT_LIST_NEXT(node), i++) {
+        derCerts[i] = node->cert->derCert;
+      }
+      nsNSSCertificateDB::ImportValidCACerts(numCAs, derCerts, ctx, locker);
+      nsMemory::Free(derCerts);
+    }
+  }
+ }
+
+  if (aDoForcedBackup) {
+    // I can't pop up a file picker from the depths of JavaScript,
+    // so I'll just post an event on the UI queue to do the backups
+    // later.
+    nsCOMPtr<nsIRunnable> p12Runnable = new nsP12Runnable(certArr, numResponses,
+                                                          token);
+    if (!p12Runnable) {
+      rv = NS_ERROR_FAILURE;
+      goto loser;
+    }
+
+    // null out the certArr pointer which has now been inherited by
+    // the nsP12Runnable instance so that we don't free up the
+    // memory on the way out.
+    certArr = nullptr;
+
+    rv = NS_DispatchToMainThread(p12Runnable);
+    if (NS_FAILED(rv))
+      goto loser;
+  }
+
+ loser:
+  if (certArr) {
+    for (i=0; i<numResponses; i++) {
+      NS_IF_RELEASE(certArr[i]);
+    }
+    delete []certArr;
+  }
+  aReturn.Assign(EmptyString());
+  if (nickname) {
+    NS_Free(nickname);
+  }
+  if (cmmfResponse) {
+    NS_Free(cmmfResponse);
+  }
+  if (certRepContent) {
+    CMMF_DestroyCertRepContent(certRepContent);
+  }
+
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
+}
+
+static void
+GetDocumentFromContext(JSContext *cx, nsIDocument **aDocument)
+{
+  // Get the script context.
+  nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx);
+  if (!scriptContext) {
+    return;
+  }
+
+  nsCOMPtr<nsIDOMWindow> domWindow = 
+    do_QueryInterface(scriptContext->GetGlobalObject());
+  if (!domWindow) {
+    return;
+  }
+
+  nsCOMPtr<nsIDOMDocument> domDocument;
+  domWindow->GetDocument(getter_AddRefs(domDocument));
+  if (!domDocument) {
+    return;
+  }
+
+  CallQueryInterface(domDocument, aDocument);
+
+  return;
+}
+
+void signTextOutputCallback(void *arg, const char *buf, unsigned long len)
+{
+  ((nsCString*)arg)->Append(buf, len);
+}
+
+void
+nsCrypto::SignText(JSContext* aContext,
+                   const nsAString& aStringToSign,
+                   const nsAString& aCaOption,
+                   const Sequence<nsCString>& aArgs,
+                   nsAString& aReturn)
+{
+  // XXX This code should return error codes, but we're keeping this
+  //     backwards compatible with NS4.x and so we can't throw exceptions.
+  NS_NAMED_LITERAL_STRING(internalError, "error:internalError");
+
+  aReturn.Truncate();
+
+  uint32_t argc = aArgs.Length();
+
+  if (!aCaOption.EqualsLiteral("auto") &&
+      !aCaOption.EqualsLiteral("ask")) {
+    NS_WARNING("caOption argument must be ask or auto");
+    aReturn.Append(internalError);
+
+    return;
+  }
+
+  // It was decided to always behave as if "ask" were specified.
+  // XXX Should we warn in the JS Console for auto?
+
+  nsCOMPtr<nsIInterfaceRequestor> uiContext = new PipUIContext;
+  if (!uiContext) {
+    aReturn.Append(internalError);
+
+    return;
+  }
+
+  bool bestOnly = true;
+  bool validOnly = true;
+  CERTCertList* certList =
+    CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), certUsageEmailSigner,
+                              bestOnly, validOnly, uiContext);
+
+  uint32_t numCAs = argc;
+  if (numCAs > 0) {
+    nsAutoArrayPtr<char*> caNames(new char*[numCAs]);
+    if (!caNames) {
+      aReturn.Append(internalError);
+      return;
+    }
+
+    uint32_t i;
+    for (i = 0; i < numCAs; ++i)
+      caNames[i] = const_cast<char*>(aArgs[i].get());
+
+    if (certList &&
+        CERT_FilterCertListByCANames(certList, numCAs, caNames,
+                                     certUsageEmailSigner) != SECSuccess) {
+      aReturn.Append(internalError);
+
+      return;
+    }
+  }
+
+  if (!certList || CERT_LIST_EMPTY(certList)) {
+    aReturn.AppendLiteral("error:noMatchingCert");
+
+    return;
+  }
+
+  nsCOMPtr<nsIFormSigningDialog> fsd =
+    do_CreateInstance(NS_FORMSIGNINGDIALOG_CONTRACTID);
+  if (!fsd) {
+    aReturn.Append(internalError);
+
+    return;
+  }
+
+  nsCOMPtr<nsIDocument> document;
+  GetDocumentFromContext(aContext, getter_AddRefs(document));
+  if (!document) {
+    aReturn.Append(internalError);
+
+    return;
+  }
+
+  // Get the hostname from the URL of the document.
+  nsIURI* uri = document->GetDocumentURI();
+  if (!uri) {
+    aReturn.Append(internalError);
+
+    return;
+  }
+
+  nsresult rv;
+
+  nsCString host;
+  rv = uri->GetHost(host);
+  if (NS_FAILED(rv)) {
+    aReturn.Append(internalError);
+
+    return;
+  }
+
+  int32_t numberOfCerts = 0;
+  CERTCertListNode* node;
+  for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
+       node = CERT_LIST_NEXT(node)) {
+    ++numberOfCerts;
+  }
+
+  ScopedCERTCertNicknames nicknames(getNSSCertNicknamesFromCertList(certList));
+
+  if (!nicknames) {
+    aReturn.Append(internalError);
+
+    return;
+  }
+
+  NS_ASSERTION(nicknames->numnicknames == numberOfCerts,
+               "nicknames->numnicknames != numberOfCerts");
+
+  nsAutoArrayPtr<char16_t*> certNicknameList(new char16_t*[nicknames->numnicknames * 2]);
+  if (!certNicknameList) {
+    aReturn.Append(internalError);
+
+    return;
+  }
+
+  char16_t** certDetailsList = certNicknameList.get() + nicknames->numnicknames;
+
+  int32_t certsToUse;
+  for (node = CERT_LIST_HEAD(certList), certsToUse = 0;
+       !CERT_LIST_END(node, certList) && certsToUse < nicknames->numnicknames;
+       node = CERT_LIST_NEXT(node)) {
+    RefPtr<nsNSSCertificate> tempCert(nsNSSCertificate::Create(node->cert));
+    if (tempCert) {
+      nsAutoString nickWithSerial, details;
+      rv = tempCert->FormatUIStrings(NS_ConvertUTF8toUTF16(nicknames->nicknames[certsToUse]),
+                                     nickWithSerial, details);
+      if (NS_SUCCEEDED(rv)) {
+        certNicknameList[certsToUse] = ToNewUnicode(nickWithSerial);
+        if (certNicknameList[certsToUse]) {
+          certDetailsList[certsToUse] = ToNewUnicode(details);
+          if (!certDetailsList[certsToUse]) {
+            nsMemory::Free(certNicknameList[certsToUse]);
+            continue;
+          }
+          ++certsToUse;
+        }
+      }
+    }
+  }
+
+  if (certsToUse == 0) {
+    aReturn.Append(internalError);
+
+    return;
+  }
+
+  NS_ConvertUTF8toUTF16 utf16Host(host);
+
+  CERTCertificate *signingCert = nullptr;
+  bool tryAgain, canceled;
+  nsAutoString password;
+  do {
+    // Throw up the form signing confirmation dialog and get back the index
+    // of the selected cert.
+    int32_t selectedIndex = -1;
+    rv = fsd->ConfirmSignText(uiContext, utf16Host, aStringToSign,
+                              const_cast<const char16_t**>(certNicknameList.get()),
+                              const_cast<const char16_t**>(certDetailsList),
+                              certsToUse, &selectedIndex, password,
+                              &canceled);
+    if (NS_FAILED(rv) || canceled) {
+      break; // out of tryAgain loop
+    }
+
+    int32_t j = 0;
+    for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
+         node = CERT_LIST_NEXT(node)) {
+      if (j == selectedIndex) {
+        signingCert = CERT_DupCertificate(node->cert);
+        break; // out of cert list iteration loop
+      }
+      ++j;
+    }
+
+    if (!signingCert) {
+      rv = NS_ERROR_FAILURE;
+      break; // out of tryAgain loop
+    }
+
+    NS_ConvertUTF16toUTF8 pwUtf8(password);
+
+    tryAgain =
+      PK11_CheckUserPassword(signingCert->slot,
+                             const_cast<char *>(pwUtf8.get())) != SECSuccess;
+    // XXX we should show an error dialog before retrying
+  } while (tryAgain);
+
+  int32_t k;
+  for (k = 0; k < certsToUse; ++k) {
+    nsMemory::Free(certNicknameList[k]);
+    nsMemory::Free(certDetailsList[k]);
+  }
+
+  if (NS_FAILED(rv)) { // something went wrong inside the tryAgain loop
+    aReturn.Append(internalError);
+
+    return;
+  }
+
+  if (canceled) {
+    aReturn.AppendLiteral("error:userCancel");
+
+    return;
+  }
+
+  SECKEYPrivateKey* privKey = PK11_FindKeyByAnyCert(signingCert, uiContext);
+  if (!privKey) {
+    aReturn.Append(internalError);
+
+    return;
+  }
+
+  nsAutoCString charset(document->GetDocumentCharacterSet());
+
+  // XXX Doing what nsFormSubmission::GetEncoder does (see
+  //     http://bugzilla.mozilla.org/show_bug.cgi?id=81203).
+  if (charset.EqualsLiteral("ISO-8859-1")) {
+    charset.AssignLiteral("windows-1252");
+  }
+
+  nsCOMPtr<nsISaveAsCharset> encoder =
+    do_CreateInstance(NS_SAVEASCHARSET_CONTRACTID);
+  if (encoder) {
+    rv = encoder->Init(charset.get(),
+                       (nsISaveAsCharset::attr_EntityAfterCharsetConv + 
+                       nsISaveAsCharset::attr_FallbackDecimalNCR),
+                       0);
+  }
+
+  nsXPIDLCString buffer;
+  if (aStringToSign.Length() > 0) {
+    if (encoder && NS_SUCCEEDED(rv)) {
+      rv = encoder->Convert(PromiseFlatString(aStringToSign).get(),
+                            getter_Copies(buffer));
+      if (NS_FAILED(rv)) {
+        aReturn.Append(internalError);
+
+        return;
+      }
+    }
+    else {
+      AppendUTF16toUTF8(aStringToSign, buffer);
+    }
+  }
+
+  HASHContext *hc = HASH_Create(HASH_AlgSHA1);
+  if (!hc) {
+    aReturn.Append(internalError);
+
+    return;
+  }
+
+  unsigned char hash[SHA1_LENGTH];
+
+  SECItem digest;
+  digest.data = hash;
+
+  HASH_Begin(hc);
+  HASH_Update(hc, reinterpret_cast<const unsigned char*>(buffer.get()),
+              buffer.Length());
+  HASH_End(hc, digest.data, &digest.len, SHA1_LENGTH);
+  HASH_Destroy(hc);
+
+  nsCString p7;
+  SECStatus srv = SECFailure;
+
+  SEC_PKCS7ContentInfo *ci = SEC_PKCS7CreateSignedData(signingCert,
+                                                       certUsageEmailSigner,
+                                                       nullptr, SEC_OID_SHA1,
+                                                       &digest, nullptr, uiContext);
+  if (ci) {
+    srv = SEC_PKCS7IncludeCertChain(ci, nullptr);
+    if (srv == SECSuccess) {
+      srv = SEC_PKCS7AddSigningTime(ci);
+      if (srv == SECSuccess) {
+        srv = SEC_PKCS7Encode(ci, signTextOutputCallback, &p7, nullptr, nullptr,
+                              uiContext);
+      }
+    }
+
+    SEC_PKCS7DestroyContentInfo(ci);
+  }
+
+  if (srv != SECSuccess) {
+    aReturn.Append(internalError);
+
+    return;
+  }
+
+  SECItem binary_item;
+  binary_item.data = reinterpret_cast<unsigned char*>
+                                     (const_cast<char*>(p7.get()));
+  binary_item.len = p7.Length();
+
+  char *result = NSSBase64_EncodeItem(nullptr, nullptr, 0, &binary_item);
+  if (result) {
+    AppendASCIItoUTF16(result, aReturn);
+  }
+  else {
+    aReturn.Append(internalError);
+  }
+
+  PORT_Free(result);
+
+  return;
+}
+
+void
+nsCrypto::Logout(ErrorResult& aRv)
+{
+  NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
+
+  nsresult rv;
+  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return;
+  }
+
+  {
+    nsNSSShutDownPreventionLock locker;
+    PK11_LogoutAll();
+    SSL_ClearSessionCache();
+  }
+
+  rv = nssComponent->LogoutAuthenticatedPK11();
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
+}
+
+CRMFObject::CRMFObject()
+{
+  MOZ_COUNT_CTOR(CRMFObject);
+}
+
+CRMFObject::~CRMFObject()
+{
+  MOZ_COUNT_DTOR(CRMFObject);
+}
+
+JSObject*
+CRMFObject::WrapObject(JSContext *aCx, bool* aTookOwnership)
+{
+  return CRMFObjectBinding::Wrap(aCx, this, aTookOwnership);
+}
+
+void
+CRMFObject::GetRequest(nsAString& aRequest)
+{
+  aRequest.Assign(mBase64Request);
+}
+
+nsresult
+CRMFObject::SetCRMFRequest(char *inRequest)
+{
+  mBase64Request.AssignWithConversion(inRequest);  
+  return NS_OK;
+}
+
+#endif // MOZ_DISABLE_CRYPTOLEGACY
+
 nsPkcs11::nsPkcs11()
 {
 }
 
 nsPkcs11::~nsPkcs11()
 {
 }
 
@@ -50,17 +2842,17 @@ nsPkcs11::DeleteModule(const nsAString& 
   }
   
   NS_ConvertUTF16toUTF8 modName(aModuleName);
   int32_t modType;
   SECStatus srv = SECMOD_DeleteModule(modName.get(), &modType);
   if (srv == SECSuccess) {
     SECMODModule *module = SECMOD_FindModule(modName.get());
     if (module) {
-#ifndef MOZ_NO_SMART_CARDS
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
       nssComponent->ShutdownSmartCardThread(module);
 #endif
       SECMOD_DestroyModule(module);
     }
     rv = NS_OK;
   } else {
     rv = NS_ERROR_FAILURE;
   }
@@ -86,17 +2878,17 @@ nsPkcs11::AddModule(const nsAString& aMo
   NS_CopyUnicodeToNative(aLibraryFullPath, fullPath);
   uint32_t mechFlags = SECMOD_PubMechFlagstoInternal(aCryptoMechanismFlags);
   uint32_t cipherFlags = SECMOD_PubCipherFlagstoInternal(aCipherFlags);
   SECStatus srv = SECMOD_AddNewModule(moduleName.get(), fullPath.get(), 
                                       mechFlags, cipherFlags);
   if (srv == SECSuccess) {
     SECMODModule *module = SECMOD_FindModule(moduleName.get());
     if (module) {
-#ifndef MOZ_NO_SMART_CARDS
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
       nssComponent->LaunchSmartCardThread(module);
 #endif
       SECMOD_DestroyModule(module);
     }
   }
 
   // The error message we report to the user depends directly on 
   // what the return value for SEDMOD_AddNewModule is
@@ -106,8 +2898,9 @@ nsPkcs11::AddModule(const nsAString& aMo
   case SECFailure:
     return NS_ERROR_FAILURE;
   case -2:
     return NS_ERROR_ILLEGAL_VALUE;
   }
   NS_ERROR("Bogus return value, this should never happen");
   return NS_ERROR_FAILURE;
 }
+
--- a/security/manager/ssl/src/nsCrypto.h
+++ b/security/manager/ssl/src/nsCrypto.h
@@ -1,16 +1,107 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * 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/. */
 #ifndef _nsCrypto_h_
 #define _nsCrypto_h_
 
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/ErrorResult.h"
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+#include "mozilla/dom/NonRefcountedDOMObject.h"
+#include "Crypto.h"
+#include "nsCOMPtr.h"
+#include "nsIDOMCryptoLegacy.h"
+#include "nsIRunnable.h"
+#include "nsString.h"
+#include "nsIPrincipal.h"
+
+#define NS_CRYPTO_CID \
+  {0x929d9320, 0x251e, 0x11d4, { 0x8a, 0x7c, 0x00, 0x60, 0x08, 0xc8, 0x44, 0xc3} }
+#define PSM_VERSION_STRING "2.4"
+
+class nsIPSMComponent;
+class nsIDOMScriptObjectFactory;
+
+namespace mozilla {
+namespace dom {
+
+class CRMFObject : public NonRefcountedDOMObject
+{
+public:
+  CRMFObject();
+  virtual ~CRMFObject();
+
+  nsresult SetCRMFRequest(char *inRequest);
+
+  JSObject* WrapObject(JSContext *aCx, bool* aTookOwnership);
+
+  void GetRequest(nsAString& aRequest);
+
+private:
+  nsString mBase64Request;
+};
+
+}
+}
+
+class nsCrypto: public mozilla::dom::Crypto
+{
+public:
+  nsCrypto();
+
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // If legacy DOM crypto is enabled this is the class that actually
+  // implements the legacy methods.
+  NS_DECL_NSIDOMCRYPTO
+
+  virtual bool EnableSmartCardEvents() MOZ_OVERRIDE;
+  virtual void SetEnableSmartCardEvents(bool aEnable,
+                                        mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
+
+  virtual void GetVersion(nsString& aVersion) MOZ_OVERRIDE;
+
+  virtual mozilla::dom::CRMFObject*
+  GenerateCRMFRequest(JSContext* aContext,
+                      const nsCString& aReqDN,
+                      const nsCString& aRegToken,
+                      const nsCString& aAuthenticator,
+                      const nsCString& aEaCert,
+                      const nsCString& aJsCallback,
+                      const mozilla::dom::Sequence<JS::Value>& aArgs,
+                      mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
+
+  virtual void ImportUserCertificates(const nsAString& aNickname,
+                                      const nsAString& aCmmfResponse,
+                                      bool aDoForcedBackup,
+                                      nsAString& aReturn,
+                                      mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
+
+  virtual void SignText(JSContext* aContext,
+                        const nsAString& aStringToSign,
+                        const nsAString& aCaOption,
+                        const mozilla::dom::Sequence<nsCString>& aArgs,
+                        nsAString& aReturn) MOZ_OVERRIDE;
+
+  virtual void Logout(mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
+
+protected:
+  virtual ~nsCrypto();
+
+private:
+  static already_AddRefed<nsIPrincipal> GetScriptPrincipal(JSContext *cx);
+
+  bool mEnableSmartCardEvents;
+};
+#endif // MOZ_DISABLE_CRYPTOLEGACY
+
 #include "nsIPKCS11.h"
 
 #define NS_PKCS11_CID \
   {0x74b7a390, 0x3b41, 0x11d4, { 0x8a, 0x80, 0x00, 0x60, 0x08, 0xc8, 0x44, 0xc3} }
 
 class nsPkcs11 : public nsIPKCS11
 {
 public:
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
@@ -18,17 +18,17 @@
 #include "nsComponentManagerUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsICertOverrideService.h"
 #include "mozilla/Preferences.h"
 #include "nsThreadUtils.h"
 #include "mozilla/PublicSSL.h"
 #include "mozilla/StaticPtr.h"
 
-#ifndef MOZ_NO_SMART_CARDS
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
 #include "nsSmartCardMonitor.h"
 #endif
 
 #include "nsCRT.h"
 #include "nsNTLMAuthModule.h"
 #include "nsIFile.h"
 #include "nsIProperties.h"
 #include "nsIWindowWatcher.h"
@@ -208,17 +208,17 @@ GetOCSPBehaviorFromPrefs(/*out*/ CertVer
        : CertVerifier::ocsp_get_disabled;
 
   SSL_ClearSessionCache();
 }
 
 nsNSSComponent::nsNSSComponent()
   :mutex("nsNSSComponent.mutex"),
    mNSSInitialized(false),
-#ifndef MOZ_NO_SMART_CARDS
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
    mThreadList(nullptr),
 #endif
    mCertVerificationThread(nullptr)
 {
 #ifdef PR_LOGGING
   if (!gPIPNSSLog)
     gPIPNSSLog = PR_NewLogModule("pipnss");
 #endif
@@ -352,17 +352,17 @@ nsNSSComponent::GetNSSBundleString(const
       outString = result;
       rv = NS_OK;
     }
   }
 
   return rv;
 }
 
-#ifndef MOZ_NO_SMART_CARDS
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
 void
 nsNSSComponent::LaunchSmartCardThreads()
 {
   nsNSSShutDownPreventionLock locker;
   {
     SECMODModuleList* list;
     SECMODListLock* lock = SECMOD_GetDefaultModuleListLock();
     if (!lock) {
@@ -408,17 +408,17 @@ nsNSSComponent::ShutdownSmartCardThread(
 }
 
 void
 nsNSSComponent::ShutdownSmartCardThreads()
 {
   delete mThreadList;
   mThreadList = nullptr;
 }
-#endif // MOZ_NO_SMART_CARDS
+#endif // MOZ_DISABLE_CRYPTOLEGACY
 
 void
 nsNSSComponent::LoadLoadableRoots()
 {
   nsNSSShutDownPreventionLock locker;
   SECMODModule* RootsModule = nullptr;
 
   // In the past we used SECMOD_AddNewModule to load our module containing
@@ -1028,17 +1028,17 @@ nsNSSComponent::InitializeNSS()
     return NS_ERROR_FAILURE;
   }
 
   // dynamic options from prefs
   setValidationOptions(true, lock);
 
   mHttpForNSS.initTable();
 
-#ifndef MOZ_NO_SMART_CARDS
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
   LaunchSmartCardThreads();
 #endif
 
   mozilla::pkix::RegisterErrorTable();
 
   // Initialize the site security service
   nsCOMPtr<nsISiteSecurityService> sssService =
     do_GetService(NS_SSSERVICE_CONTRACTID);
@@ -1067,17 +1067,17 @@ nsNSSComponent::ShutdownNSS()
 
     PK11_SetPasswordFunc((PK11PasswordFunc)nullptr);
 
     Preferences::RemoveObserver(this, "security.");
     if (NS_FAILED(CipherSuiteChangeObserver::StopObserve())) {
       PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("nsNSSComponent::ShutdownNSS cannot stop observing cipher suite change\n"));
     }
 
-#ifndef MOZ_NO_SMART_CARDS
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
     ShutdownSmartCardThreads();
 #endif
     SSL_ClearSessionCache();
     UnloadLoadableRoots();
 #ifndef MOZ_NO_EV_CERTS
     CleanupIdentityInfo();
 #endif
     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("evaporating psm resources\n"));
--- a/security/manager/ssl/src/nsNSSComponent.h
+++ b/security/manager/ssl/src/nsNSSComponent.h
@@ -9,16 +9,18 @@
 
 #include "mozilla/Mutex.h"
 #include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIEntropyCollector.h"
 #include "nsIStringBundle.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+#endif
 #include "nsINSSErrorsService.h"
 #include "nsNSSCallbacks.h"
 #include "SharedCertVerifier.h"
 #include "nsNSSHelper.h"
 #include "nsClientAuthRemember.h"
 #include "prerror.h"
 
 class nsIDOMWindow;
@@ -80,17 +82,17 @@ class NS_NO_VTABLE nsINSSComponent : pub
                                 nsAString& outString) = 0;
   NS_IMETHOD NSSBundleFormatStringFromName(const char* name,
                                            const char16_t** params,
                                            uint32_t numParams,
                                            nsAString& outString) = 0;
 
   NS_IMETHOD LogoutAuthenticatedPK11() = 0;
 
-#ifndef MOZ_NO_SMART_CARDS
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
   NS_IMETHOD LaunchSmartCardThread(SECMODModule* module) = 0;
 
   NS_IMETHOD ShutdownSmartCardThread(SECMODModule* module) = 0;
 #endif
 
   NS_IMETHOD IsNSSInitialized(bool* initialized) = 0;
 
   virtual ::mozilla::TemporaryRef<mozilla::psm::SharedCertVerifier>
@@ -133,17 +135,17 @@ public:
                                            nsAString& outString);
   NS_IMETHOD GetNSSBundleString(const char* name, nsAString& outString);
   NS_IMETHOD NSSBundleFormatStringFromName(const char* name,
                                            const char16_t** params,
                                            uint32_t numParams,
                                            nsAString& outString);
   NS_IMETHOD LogoutAuthenticatedPK11();
 
-#ifndef MOZ_NO_SMART_CARDS
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
   NS_IMETHOD LaunchSmartCardThread(SECMODModule* module);
   NS_IMETHOD ShutdownSmartCardThread(SECMODModule* module);
   void LaunchSmartCardThreads();
   void ShutdownSmartCardThreads();
   nsresult DispatchEventToWindow(nsIDOMWindow* domWin,
                                  const nsAString& eventType,
                                  const nsAString& token);
 #endif
@@ -180,17 +182,17 @@ private:
   Mutex mutex;
 
   nsCOMPtr<nsIStringBundle> mPIPNSSBundle;
   nsCOMPtr<nsIStringBundle> mNSSErrorsBundle;
   bool mNSSInitialized;
   bool mObserversRegistered;
   static int mInstanceCount;
   nsNSSShutDownList* mShutdownObjectList;
-#ifndef MOZ_NO_SMART_CARDS
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
   SmartCardThreadList* mThreadList;
 #endif
   bool mIsNetworkDown;
 
   void deleteBackgroundThreads();
   void createBackgroundThreads();
   nsCertVerificationThread* mCertVerificationThread;
 
--- a/security/manager/ssl/src/nsNSSModule.cpp
+++ b/security/manager/ssl/src/nsNSSModule.cpp
@@ -185,16 +185,19 @@ NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_BYPRO
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsNSSCertificateDB)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsNSSCertCache)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_BYPROCESS(nssEnsureOnChromeOnly,
                                              nsNSSCertList,
                                              nsNSSCertListFakeTransport)
 #ifdef MOZ_XUL
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCertTree)
 #endif
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCrypto)
+#endif
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsPkcs11)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCertPicker)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nssEnsure, nsNTLMAuthModule, InitTest)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCryptoHash)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCryptoHMAC)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsStreamCipher)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsKeyObject)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsKeyObjectFactory)
@@ -219,16 +222,19 @@ NS_DEFINE_NAMED_CID(NS_X509CERT_CID);
 NS_DEFINE_NAMED_CID(NS_X509CERTDB_CID);
 NS_DEFINE_NAMED_CID(NS_X509CERTLIST_CID);
 NS_DEFINE_NAMED_CID(NS_NSSCERTCACHE_CID);
 NS_DEFINE_NAMED_CID(NS_FORMPROCESSOR_CID);
 #ifdef MOZ_XUL
 NS_DEFINE_NAMED_CID(NS_CERTTREE_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_PKCS11_CID);
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+NS_DEFINE_NAMED_CID(NS_CRYPTO_CID);
+#endif
 NS_DEFINE_NAMED_CID(NS_CRYPTO_HASH_CID);
 NS_DEFINE_NAMED_CID(NS_CRYPTO_HMAC_CID);
 NS_DEFINE_NAMED_CID(NS_CERT_PICKER_CID);
 NS_DEFINE_NAMED_CID(NS_NTLMAUTHMODULE_CID);
 NS_DEFINE_NAMED_CID(NS_STREAMCIPHER_CID);
 NS_DEFINE_NAMED_CID(NS_KEYMODULEOBJECT_CID);
 NS_DEFINE_NAMED_CID(NS_KEYMODULEOBJECTFACTORY_CID);
 NS_DEFINE_NAMED_CID(NS_DATASIGNATUREVERIFIER_CID);
@@ -251,16 +257,19 @@ static const mozilla::Module::CIDEntry k
   { &kNS_X509CERTDB_CID, false, nullptr, nsNSSCertificateDBConstructor },
   { &kNS_X509CERTLIST_CID, false, nullptr, nsNSSCertListConstructor },
   { &kNS_NSSCERTCACHE_CID, false, nullptr, nsNSSCertCacheConstructor },
   { &kNS_FORMPROCESSOR_CID, false, nullptr, nsKeygenFormProcessor::Create },
 #ifdef MOZ_XUL
   { &kNS_CERTTREE_CID, false, nullptr, nsCertTreeConstructor },
 #endif
   { &kNS_PKCS11_CID, false, nullptr, nsPkcs11Constructor },
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+  { &kNS_CRYPTO_CID, false, nullptr, nsCryptoConstructor },
+#endif
   { &kNS_CRYPTO_HASH_CID, false, nullptr, nsCryptoHashConstructor },
   { &kNS_CRYPTO_HMAC_CID, false, nullptr, nsCryptoHMACConstructor },
   { &kNS_CERT_PICKER_CID, false, nullptr, nsCertPickerConstructor },
   { &kNS_NTLMAUTHMODULE_CID, false, nullptr, nsNTLMAuthModuleConstructor },
   { &kNS_STREAMCIPHER_CID, false, nullptr, nsStreamCipherConstructor },
   { &kNS_KEYMODULEOBJECT_CID, false, nullptr, nsKeyObjectConstructor },
   { &kNS_KEYMODULEOBJECTFACTORY_CID, false, nullptr, nsKeyObjectFactoryConstructor },
   { &kNS_DATASIGNATUREVERIFIER_CID, false, nullptr, nsDataSignatureVerifierConstructor },
@@ -286,16 +295,19 @@ static const mozilla::Module::ContractID
   { NS_X509CERTDB_CONTRACTID, &kNS_X509CERTDB_CID },
   { NS_X509CERTLIST_CONTRACTID, &kNS_X509CERTLIST_CID },
   { NS_NSSCERTCACHE_CONTRACTID, &kNS_NSSCERTCACHE_CID },
   { NS_FORMPROCESSOR_CONTRACTID, &kNS_FORMPROCESSOR_CID },
 #ifdef MOZ_XUL
   { NS_CERTTREE_CONTRACTID, &kNS_CERTTREE_CID },
 #endif
   { NS_PKCS11_CONTRACTID, &kNS_PKCS11_CID },
+#ifndef MOZ_DISABLE_CRYPTOLEGACY
+  { NS_CRYPTO_CONTRACTID, &kNS_CRYPTO_CID },
+#endif
   { NS_CRYPTO_HASH_CONTRACTID, &kNS_CRYPTO_HASH_CID },
   { NS_CRYPTO_HMAC_CONTRACTID, &kNS_CRYPTO_HMAC_CID },
   { NS_CERT_PICKER_CONTRACTID, &kNS_CERT_PICKER_CID },
   { "@mozilla.org/uriloader/psm-external-content-listener;1", &kNS_PSMCONTENTLISTEN_CID },
   { NS_CRYPTO_FIPSINFO_SERVICE_CONTRACTID, &kNS_PKCS11MODULEDB_CID },
   { NS_NTLMAUTHMODULE_CONTRACTID, &kNS_NTLMAUTHMODULE_CID },
   { NS_STREAMCIPHER_CONTRACTID, &kNS_STREAMCIPHER_CID },
   { NS_KEYMODULEOBJECT_CONTRACTID, &kNS_KEYMODULEOBJECT_CID },
--- a/security/manager/ssl/src/nsSmartCardMonitor.cpp
+++ b/security/manager/ssl/src/nsSmartCardMonitor.cpp
@@ -1,22 +1,29 @@
 /* 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/. */
 #include "nspr.h"
 
+#include "mozilla/dom/SmartCardEvent.h"
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
+#include "nsIDOMCryptoLegacy.h"
+#include "nsIDOMDocument.h"
+#include "nsIDOMWindow.h"
+#include "nsIDOMWindowCollection.h"
 #include "nsIObserverService.h"
+#include "nsISimpleEnumerator.h"
+#include "nsIWindowWatcher.h"
 #include "nsServiceManagerUtils.h"
 #include "nsSmartCardMonitor.h"
-#include "nsThreadUtils.h"
 #include "pk11func.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 //
 // The SmartCard monitoring thread should start up for each module we load
 // that has removable tokens. This code calls an NSS function which waits
 // until there is a change in the token state. NSS uses the
 // C_WaitForSlotEvent() call in PKCS #11 if the module implements the call,
 // otherwise NSS will poll the token in a loop with a delay of 'latency'
 // between polls. Note that the C_WaitForSlotEvent() may wake up on any type
@@ -38,16 +45,17 @@ public:
   {
   }
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIRUNNABLE
 
 private:
   virtual ~nsTokenEventRunnable() {}
+  nsresult DispatchEventToWindow(nsIDOMWindow* domWin);
 
   nsString mType;
   nsString mTokenName;
 };
 
 NS_IMPL_ISUPPORTS(nsTokenEventRunnable, nsIRunnable)
 
 NS_IMETHODIMP
@@ -58,18 +66,131 @@ nsTokenEventRunnable::Run()
   nsCOMPtr<nsIObserverService> observerService =
     mozilla::services::GetObserverService();
   if (!observerService) {
     return NS_ERROR_FAILURE;
   }
   // This conversion is safe because mType can only be "smartcard-insert"
   // or "smartcard-remove".
   NS_ConvertUTF16toUTF8 eventTypeUTF8(mType);
-  return observerService->NotifyObservers(nullptr, eventTypeUTF8.get(),
-                                          mTokenName.get());
+  nsresult rv = observerService->NotifyObservers(nullptr, eventTypeUTF8.get(),
+                                                 mTokenName.get());
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  // 'Dispatch' the event to all the windows. 'DispatchEventToWindow()' will
+  // first check to see if a given window has requested crypto events.
+  nsCOMPtr<nsIWindowWatcher> windowWatcher =
+    do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  nsCOMPtr<nsISimpleEnumerator> enumerator;
+  rv = windowWatcher->GetWindowEnumerator(getter_AddRefs(enumerator));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  for (;;) {
+    bool hasMoreWindows;
+    rv = enumerator->HasMoreElements(&hasMoreWindows);
+    if (NS_FAILED(rv) || !hasMoreWindows) {
+      return rv;
+    }
+    nsCOMPtr<nsISupports> supports;
+    enumerator->GetNext(getter_AddRefs(supports));
+    nsCOMPtr<nsIDOMWindow> domWin(do_QueryInterface(supports));
+    if (domWin) {
+      rv = DispatchEventToWindow(domWin);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+    }
+  }
+  return rv;
+}
+
+nsresult
+nsTokenEventRunnable::DispatchEventToWindow(nsIDOMWindow* domWin)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(domWin);
+
+  // first walk the children and dispatch their events
+  nsCOMPtr<nsIDOMWindowCollection> frames;
+  nsresult rv = domWin->GetFrames(getter_AddRefs(frames));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  uint32_t length;
+  rv = frames->GetLength(&length);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  for (uint32_t i = 0; i < length; i++) {
+    nsCOMPtr<nsIDOMWindow> childWin;
+    rv = frames->Item(i, getter_AddRefs(childWin));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    if (domWin) {
+      rv = DispatchEventToWindow(childWin);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+    }
+  }
+
+  // check if we've enabled smart card events on this window
+  // NOTE: it's not an error to say that we aren't going to dispatch
+  // the event.
+  nsCOMPtr<nsIDOMCrypto> crypto;
+  rv = domWin->GetCrypto(getter_AddRefs(crypto));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  if (!crypto) {
+    return NS_OK; // nope, it doesn't have a crypto property
+  }
+
+  bool boolrv;
+  rv = crypto->GetEnableSmartCardEvents(&boolrv);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  if (!boolrv) {
+    return NS_OK; // nope, it's not enabled.
+  }
+
+  // dispatch the event ...
+
+  // find the document
+  nsCOMPtr<nsIDOMDocument> doc;
+  rv = domWin->GetDocument(getter_AddRefs(doc));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  if (!doc) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<EventTarget> d = do_QueryInterface(doc);
+
+  SmartCardEventInit init;
+  init.mBubbles = false;
+  init.mCancelable = true;
+  init.mTokenName = mTokenName;
+
+  nsRefPtr<SmartCardEvent> event(SmartCardEvent::Constructor(d, mType, init));
+  event->SetTrusted(true);
+
+  return d->DispatchEvent(event, &boolrv);
 }
 
 // self linking and removing double linked entry
 // adopts the thread it is passed.
 class SmartCardThreadEntry
 {
 public:
   friend class SmartCardThreadList;
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/bugs/mochitest-legacy.ini
@@ -0,0 +1,2 @@
+[test_generateCRMFRequest.html]
+skip-if = e10s
\ No newline at end of file
--- a/security/manager/ssl/tests/mochitest/bugs/moz.build
+++ b/security/manager/ssl/tests/mochitest/bugs/moz.build
@@ -1,9 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=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/.
 
 MOCHITEST_MANIFESTS += ['mochitest.ini']
+# test_generateCRMFRequest.html tests crypto.generateCRMFRequest, which isn't
+# available if legacy crypto has been disabled.
+if not CONFIG['MOZ_DISABLE_CRYPTOLEGACY']:
+    MOCHITEST_MANIFESTS += ['mochitest-legacy.ini']
+
 MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
 
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/bugs/test_generateCRMFRequest.html
@@ -0,0 +1,146 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>crypto.generateCRMFRequest bugs</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="onWindowLoad()">
+<script class="testbody" type="text/javascript">
+
+  SimpleTest.waitForExplicitFinish();
+
+  function onWindowLoad() {
+    SpecialPowers.pushPrefEnv({"set": [["dom.unsafe_legacy_crypto.enabled", true]]},
+                              runTest);
+  }
+
+  function runTest() {
+    // Does it work at all?
+    try {
+      var crmfObject = crypto.generateCRMFRequest("CN=undefined", "regToken",
+                                                  "authenticator", null, "",
+                                                  512, null, "  rsa-ex   ",
+                                                  1024, null, "\r\n\t rsa-sign\t");
+      ok(true, "no exception thrown in generateCRMFRequest");
+    } catch (e) {
+      ok(false, "unexpected exception: " + e);
+    }
+
+    // bug 849553
+    // This should fail because 8 is too small of a key size.
+    try {
+      var crmfObject = crypto.generateCRMFRequest("CN=undefined", "regToken",
+                                                  "authenticator", null, "",
+                                                  8, null, "rsa-ex",
+                                                  1024, null, "rsa-sign");
+      ok(false, "execution should not reach this line");
+    } catch (e) {
+      is(e.toString(), "Error: error:could not generate the key for algorithm rsa-ex", "expected exception");
+    }
+    // This should fail because 65536 is too large of a key size.
+    try {
+      var crmfObject = crypto.generateCRMFRequest("CN=undefined", "regToken",
+                                                  "authenticator", null, "",
+                                                  65536, null, "rsa-ex",
+                                                  1024, null, "rsa-sign");
+      ok(false, "execution should not reach this line");
+    } catch (e) {
+      is(e.toString(), "Error: error:could not generate the key for algorithm rsa-ex", "expected exception");
+    }
+
+    // bug 882865
+    var o200 = document.documentElement;
+    var o1 = crypto;
+    try {
+      o1.generateCRMFRequest("undefined", o200, 'X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X', null, o1, 1404343237, Math.PI, []);
+      ok(false, "execution should not reach this line");
+    } catch (e) {
+      // The 'key generation argument' in this case was an empty array,
+      // which gets interpreted as an empty string.
+      is(e.toString(), "Error: error:invalid key generation argument:", "expected exception");
+    }
+
+    // Test that an rsa certificate isn't used to generate an ec key.
+    try {
+      var crmfObject = crypto.generateCRMFRequest("CN=a", "a", "a", null, "",
+                         1024, "popcert=MIIBjzCB+aADAgECAgUAnVC3BjANBgkqhkiG9w0BAQUFADAMMQowCAYDVQQDEwFhMB4XDTEzMTEwNjE3NDU1NFoXDTIzMTEwNjE3NDU1NFowDDEKMAgGA1UEAxMBYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3G2mwjE8IGVwv6H1NGZFSKE3UrTsgez2DtNIYb5zdi0P0w9SbmL2GWfveu9DZhRebhVz7QSMPKLagI4aoIzoP5BxRl7a8wR5wbU0z8qXnAvy9p3Ex5oN5vX47TWB7cnItoWpi6A81GSn5X1CFFHhVCEwnQsHuWXrEvLD5hrfdmcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQCNo+yLKfAd2NBI5DUpwgHSFBA+59pdNtHY7E2KZjyc9tXN6PHkPp8nScVCtk0g60j4aiiZQm8maPQPLo7Hipgpk83iYqquHRvcJVX4fWJpS/7vX+qTNT0hRiKRhVlI6S4Ttp2J2W6uxy2xxeqC6nBbU98QmDj3UQAY31LyejbecQ==", "ec-dual-use");
+      ok(crmfObject, "generateCRMFRequest succeeded");
+      var request = crmfObject.request;
+      var bytes = atob(request.replace(/\r\n/g, ""));
+
+      // rsaEncryption oid encoded in the request (as ASN1)
+      var badIdentifier = [ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
+                            0x01, 0x01, 0x01 ];
+      ok(!findIdentifierInString(badIdentifier, bytes),
+         "didn't find bad identifier in request");
+
+      // secp256r1 encoded in the request (as ASN1) (this is the default for
+      // a "1024-bit" ec key)
+      var goodIdentifier = [ 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03,
+                             0x01, 0x07 ];
+      ok(findIdentifierInString(goodIdentifier, bytes),
+         "found good identifier in request");
+    } catch (e) {
+      ok(false, "unexpected exception: " + e);
+    }
+
+    // Test that only the first of repeated keygen parameters are used.
+    try {
+      var curveCrmfObject = crypto.generateCRMFRequest("CN=a", "a", "a", null,
+                              "", 1024, "curve=secp521r1;curve=nistp384",
+                              "ec-dual-use");
+      ok(curveCrmfObject, "generateCRMFRequest succeeded");
+      var curveRequest = curveCrmfObject.request;
+      var curveBytes = atob(curveRequest.replace(/\r\n/g, ""));
+
+      // nistp384 encoded in the request (as ASN1)
+      var badIdentifier = [ 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22 ];
+      ok(!findIdentifierInString(badIdentifier, curveBytes),
+         "didn't find bad identifier in curve request");
+
+      // secp512r1 encoded in the request (as ASN1)
+      var goodIdentifier = [ 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23 ];
+      ok(findIdentifierInString(goodIdentifier, curveBytes),
+         "found good identifier in curve request");
+
+      // The popcert=MII... values are base-64 encodings of self-signed
+      // certificates. The key of the first one is a secp521r1 key, whereas
+      // the second is nistp384.
+      var popcertCrmfObject = crypto.generateCRMFRequest("CN=a", "a", "a",
+                                null, "", 1024, "popcert=MIIBjjCB8aADAgECAgUAnVEmVTAJBgcqhkjOPQQBMAwxCjAIBgNVBAMTAWkwHhcNMTMxMTA2MjE1NDUxWhcNMTQwMjA2MjE1NDUxWjAMMQowCAYDVQQDEwFpMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQA5juM0J3Od2Ih4s0ZiTkzVkh96J4yO12/L71df3GWy/Ex3LaGcew/EucY5ZITEqNHn22+3pKf3pwL6GJ/zA/foJwBspiE42ITo2BHHXl2Uuf1QK70UH5gzaqf1Cc4lPv3ibOf3EAmHx0a8sdDxRlUN2+V38iYWnMmV1qf4jM15fsYEDMwCQYHKoZIzj0EAQOBjAAwgYgCQgDO34oQkVDNkwtto1OAEbFZgq1xP9aqc+Nt7vnOuEGTISdFXCjlhon7SysTejFhO8d8wG500NrlJEmaie9FJbmWpQJCARcVtnC0K+ilxz307GyuANTaLEd7vBJxTAho8l6xkibNoxY1D9+hcc6ECbK7PCtAaysZoAVx5XhJlsnFdJdDj3wG;popcert=MIIBRDCBy6ADAgECAgUAnVEotzAJBgcqhkjOPQQBMAwxCjAIBgNVBAMTAWkwHhcNMTMxMTA2MjIwMDExWhcNMTQwMjA2MjIwMDExWjAMMQowCAYDVQQDEwFpMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEXjFpZ9bodzikeN4C8p2mVj1Ia1t+8zIndSavQHmxaD3+kvhkt18+P20ZagfBOaVEQZdArZ6KxBeW9oYZqaNpqHLveGlKYi6u9z5FyozAx4MXzyLdfu+bzOLIsryKRnLFMAkGByqGSM49BAEDaQAwZgIxAJDawIJLQ5iZsJVC3vV1YEKsI2aNEicdZ3YTMp/zUy+64Z2/cjyyfa7d5m1xKLDBogIxANHOQoy/7DioCyWNDDzx5QK0M24dOURVWRXsxjAjrg4vDmV/fkVzwpUzIr5fMgXEyQ==", "ec-dual-use");
+      ok(popcertCrmfObject, "generateCRMFRequest succeeded");
+      var popcertRequest = popcertCrmfObject.request;
+      var popcertBytes = atob(popcertRequest.replace(/\r\n/g, ""));
+      ok(!findIdentifierInString(badIdentifier, popcertBytes),
+         "didn't find bad identifier in popcert request");
+
+      ok(findIdentifierInString(goodIdentifier, popcertBytes),
+         "found good identifier in popcert request");
+    } catch (e) {
+      ok(false, "unexpected exception: " + e);
+    }
+    SimpleTest.finish();
+  }
+
+  function findIdentifierInString(identifier, str) {
+    var matches = 0;
+    for (var i = 0; i < str.length - identifier.length;
+         i += (matches != 0 ? matches : 1)) {
+      matches = 0;
+      for (var j = 0; j < identifier.length; j++) {
+        if (identifier[j] == str.charCodeAt(i + j)) {
+          matches++;
+        } else {
+          break;
+        }
+      }
+      if (matches == identifier.length) {
+        return true;
+      }
+    }
+    return false;
+  }
+</script>
+</body>
+</html>
--- a/security/manager/ssl/tests/moz.build
+++ b/security/manager/ssl/tests/moz.build
@@ -12,10 +12,10 @@ TEST_DIRS += [
 ]
 
 TEST_DIRS += [
   'compiled',
 ]
 
 XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
 
-if not CONFIG['MOZ_NO_SMART_CARDS']:
+if not CONFIG['MOZ_DISABLE_CRYPTOLEGACY']:
     XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell-smartcards.ini']
--- a/security/manager/ssl/tests/unit/moz.build
+++ b/security/manager/ssl/tests/unit/moz.build
@@ -1,10 +1,10 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=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/.
 
 DIRS += ['tlsserver']
 
-if not CONFIG['MOZ_NO_SMART_CARDS']:
+if not CONFIG['MOZ_DISABLE_CRYPTOLEGACY']:
     DIRS += ['pkcs11testmodule']