From 8395472f8d4c5b84416cc7d7bdc52747ead135a1 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 28 Apr 2014 22:16:49 -0400 Subject: [PATCH] test index.jar signature checking I got scared by seeing the Android docs' version of JarFile.getInputStream, which didn't mention SecurityException or the signature checking. But it seems that even tho its not in the Android docs, Android implements it the same as Java does. It is good to have these tests in place anyhow, since this is an essential piece of the security process of FDroid. * http://docs.oracle.com/javase/6/docs/api/java/util/jar/JarFile.html#getInputStream(java.util.zip.ZipEntry) * https://developer.android.com/reference/java/util/jar/JarFile.html#getInputStream(java.util.zip.ZipEntry) refs #2627 https://dev.guardianproject.info/issues/2627 refs #2959 https://dev.guardianproject.info/issues/2959 --- .../fdroid/updater/SignedRepoUpdater.java | 7 + test/assets/simpleIndex.jar | Bin 0 -> 2412 bytes test/assets/simpleIndex.xml | 6 + .../simpleIndexWithCorruptedCertificate.jar | Bin 0 -> 2385 bytes .../simpleIndexWithCorruptedEverything.jar | Bin 0 -> 2489 bytes .../simpleIndexWithCorruptedManifest.jar | Bin 0 -> 2384 bytes .../simpleIndexWithCorruptedSignature.jar | Bin 0 -> 2384 bytes test/assets/simpleIndexWithoutSignature.jar | Bin 0 -> 1254 bytes .../fdroid/updater/SignedRepoUpdaterTest.java | 142 ++++++++++++++++++ 9 files changed, 155 insertions(+) create mode 100644 test/assets/simpleIndex.jar create mode 100644 test/assets/simpleIndex.xml create mode 100644 test/assets/simpleIndexWithCorruptedCertificate.jar create mode 100644 test/assets/simpleIndexWithCorruptedEverything.jar create mode 100644 test/assets/simpleIndexWithCorruptedManifest.jar create mode 100644 test/assets/simpleIndexWithCorruptedSignature.jar create mode 100644 test/assets/simpleIndexWithoutSignature.jar create mode 100644 test/src/org/fdroid/fdroid/updater/SignedRepoUpdaterTest.java diff --git a/src/org/fdroid/fdroid/updater/SignedRepoUpdater.java b/src/org/fdroid/fdroid/updater/SignedRepoUpdater.java index f7ac7e805..57fdeb373 100644 --- a/src/org/fdroid/fdroid/updater/SignedRepoUpdater.java +++ b/src/org/fdroid/fdroid/updater/SignedRepoUpdater.java @@ -52,6 +52,13 @@ public class SignedRepoUpdater extends RepoUpdater { InputStream input = null; OutputStream output = null; try { + /* + * JarFile.getInputStream() provides the signature check, even + * though the Android docs do not mention this, the Java docs do + * and Android seems to implement it the same: + * http://docs.oracle.com/javase/6/docs/api/java/util/jar/JarFile.html#getInputStream(java.util.zip.ZipEntry) + * https://developer.android.com/reference/java/util/jar/JarFile.html#getInputStream(java.util.zip.ZipEntry) + */ input = jarFile.getInputStream(indexEntry); output = new FileOutputStream(indexFile); Utils.copy(input, output); diff --git a/test/assets/simpleIndex.jar b/test/assets/simpleIndex.jar new file mode 100644 index 0000000000000000000000000000000000000000..1c173ceb37eb2898f6dbb0df4a9dc849d943c919 GIT binary patch literal 2412 zcma)82{hDe8z0LsvXpG)VsdH7GPcYZQK@E%F-(YS8QmBRS!xiYELVM|L?jwnK9$Iq zE&GQoX_PTz#uhSCx3M(VM9me$9i4M=`@Zv?@A;qqIq!Sk^ZT9WJn!@Veh(HcA}S96 zfj|K9qMQ?eZ6PmMV~|c(`qp+R1B{iOH45qI1jV2hF$}sbS|8dYjn>y;GFVj(hW#e* z$B9rIjGi^7C;W-1MCSBfYPPZt;SZ(#kjY0nW|K+^V@mt)0y55jCN2<{_fHhM9l%c% zJaYbcW^CdU5qQ~5d8z?lDAHBq09ukfcqy4-u*gjMbTKK623jfwSu^YwW%_Pa1G!=V zELt3-pfAUY5o8xH__6aFeaUu`_i%|A92%$2*m$A6fux5%3p=Ar6`g>mtvPY z(_$^bBGQD7kAk2#WHF~@LG>+Z4l8nJq7 zhH0N>S2{sZxBhb1sL$m1e8Li_rnx!xdpXqLBe%K)rC9l&owhrF~G!z9henOzYw zk<*ZqyD1cct`;)zkk)`>Z{B?nCj|Z}R9mvnura#~eLBWB@j>Qqpi|deGwb#lX;nNj zLui;795Q7cwaXdornXW$Mp|228AFCPIfK;h*4}PV=YCqr%jFK}IlRxW!81OFgc*E5 zApRFGZrNlmUHfOgUuSk~o3Sa9A3;%=QAD^^C9Qn;y=-nyWHvNIQLo`C8NOb|VtT&0 zrkoqz0tV_0(Mzi5Mko3mkHGJB^`F&P)w3LU>hos78$5MW^`04+@6h0EO#pY-D0=2z5S~3Qq+#;O?d%laSZk z+teK|eYwUBj?J5i?We{p^uPE7tA2_XGqI@@=NIrNu97>RH{8FCp?EzjT;Z3~w)4OFx-A)6m1&Rji#o)XaOH zfc8~1K8e0m(UjMX)im|TrN^By;uOB?gY}FuLDM zI1jRjJ+Q!MKHZV3nJ}rOQ#WJ?!$&cgqJWjqI)Yv1UAWOZcQOFl%*$T|yyUzBtrWd_#5_Q*rKHxv4=N-E-{~J7jbfY{5jv zT0mBp^8EB6I_8bb!wOpete%=|4py-IaAP{!z;9v*x3-py8z^`l%IpO`oNh~UwH;Mq zAK}D!BIyp_JGeJrVK`P80N5e2{XvWUAV?Ab(X9?%>jVHqzJmpQ4G>_z$CeuWCl~`mJ28*c(+4@!W}(D?QcN7P~yYNHfEA|tzX6RO79&ET)(?n zA;H$&;!#m3NbPX+5!EiZ>wr;S9^^_K?Ml?)rCLV5C0MbZ;rnSWirw%oRt-8yq2+Kj z?fd3=Ewd|k>OH1iNYPm;cuDQgzQ=zCh<_`f$43D4SFjP1vWW#M(aZ`h{>f;aYwiHV ziJErs70-=0^bk?4HM&clUXXU8iX&;TVbOzj$AFliM+6y`#@2 z%$3qVXCKBqcRzb@-ru9Aj^D^zFV^+uu6Ihz<;2l5+05i&VdrZ$KMTq+m&=%0GbNDF+5U_7Ziv+=MHom+Fx1m&^9U17&x+L%3%G0lh~r zBxXQfx3~7AYoK?%4jGx>FanOlE+;A(gf8-ciD5z9ltI1jMU(}|_ zCk6E?B|B-}3(R6EiPU>dkgPicN?EuG`ggurnew65Jjq;IY|1=)}v_Rn+ zZCuB-hl&)npSXnBxG5FmveI|%o_(#d-e?e_{L#NBYPw##uIb!sCpY4kX4!DA+rf-L zVB#o_<2Ysd3j37}+5I6W=t6VDu$PYMuOT=tv%NBmaz3mvOdaA6Bc5(cyd)QHcVHLA zR^RXIt}NskQ0Nm(^|L}70;xoK#b#H5Qb(#@nkTBd>iKQhA!mA-rmXL*;)Ke5Q!Rq& zfVIzCNhC6`l$h*LxjQpROojw@wFGz!t?u(ehIpW`dmKEgTm=s@?k@#%TrSL zYcONAiShA^V9h=$@jDrmi*Ldvm*-Lpye3A)cbaFZHr)#H^bBVOPJJ`-l>(D< z>ckh9i3piO%S)!5lFW)2P-8waNh;YR#KW!FV*gR^?qDP*7)zi&NFQmZ{ zOeKAu5^$uFuhC$zNGn+kKSyGnn0=H%cn*dJmra|sjEt}?z%C|v^P|h8H)z$x@Ft@r zwXlfD)l-b$QMp-Qjb-}{bG5!%rnyJ(4l95gZ&65C9V=`P!bg&!HV zd)40=S_NdA44eMsi29LXyH;#?+E%cH{u_h9;kHx!r3-&4#)hbD#cjc6Gl>m}`4PIk eIuctr!HOw>ZVC(*4HVlr1qwcdAT3qU#_mtJ{_K$e literal 0 HcmV?d00001 diff --git a/test/assets/simpleIndex.xml b/test/assets/simpleIndex.xml new file mode 100644 index 000000000..a806ef68a --- /dev/null +++ b/test/assets/simpleIndex.xml @@ -0,0 +1,6 @@ + +The official repository of the F-Droid client. Applications in this repository +are either official binaries built by the original application developers, or +are binaries built from source by the admin of f-droid.org using the tools on +https://gitorious.org/f-droid. + \ No newline at end of file diff --git a/test/assets/simpleIndexWithCorruptedCertificate.jar b/test/assets/simpleIndexWithCorruptedCertificate.jar new file mode 100644 index 0000000000000000000000000000000000000000..ba16c33066c566f9afae7bda2fbf7cd6883f6bf2 GIT binary patch literal 2385 zcmZ{l2|SefAIBfZFxF8L%3`uKTmb|Jg?t#e?PC!@AZ6tpSLxNhj%{!fWZKNQO+rG zH8DB?0Dw5o;5-G;2s=|XGfSj8+SJkviLkYUp^=MdD#Ze&2J00@sVUQ_^lBT8e(m?; zc$hg_)ePMm`h-^?bNXO=wv;mN56Q#O$w$h1lak_Nl85gC>E}P=7x1fxCkma9U?&P5 zIefGqoA`tWUDlJDYQPrqbl2E`mjsVqN}{SS(h@&iObj7|mrB8ARLez?zFQ;^ix05= zAHTBjkz3sypXQ zhB`~|PI!=c1$^e3Q)b;EO~uMbdiwI(>c@2GCYCvaJ?*XSog=NSt<)h6^PIu-%vFgsPKBT z;0c+!DRWN`LU)ZQhS%ERR+8dkn+MNth7low_5xu!9#L;{7pR*S1xtOzmXDP7t|J*N z2Q5u)Ee)8%(G++Jr~z{~8Ig#%=F%o-dujO^D=;Q+CZ@lgu+abflP;+O%V%IjCi~cI zonvjNq`E{oveyq)SFxU9U(U}gAG1;9C6&AMJ@BiF2wIzIZE5idnR;3`hkmi${4&Xq`q~s%*;Zu~yLW#iYgBYcdO;_r1#%y{#{L zVbHSk#2?F|_c|$6bykzz7pOh&1sn$H_+DNAr(QkbGMTzUiDzzz;D$}m=%R(^uZ9kV zVJ!)bLo*cOd~O7L3_5)nLuUFBw6j8xTVpBE}H9v6Sbd230m_Tpboy{4Z&0vN=%P=);ZaXmy{7 zAG+26TrV#K#2;xym91hGPu5nKz+6r&C6hr* z8s>I*2R0cMH*$zdNbyo(Ipheyn23-&0mAjp}tAv;8 z5FMAx4#WLL_qjk>_Wr;tlM4yy(AOQU{iqt)U5{g$1~)W8!VQvgZP=SV$nHUO9i@MSD7CrBj*d-oXs%CCd15-VbDm#59^ajVlcmNhm#W3^I3?EXHJ|?b$c`T6(KdJxJ=KZ*Syu zy;5D1`)fOA{BpBsD9ib1x<4pk6vMQg(s^n9g#q37At&HMbHlKQvd%9-7#6LgDkS54 zNMnc`)K?dOwk_e3Sg7TZy%`p2K411`A?(4yPtc^Nh32@35~+3by#()il10Z$c(l=aSVuCPw-9 z7-Y#b-3oAX3#I!{t!a7-L5MkZ{EMr2eUU<=OFGPw%t`{dF&~jAl;leAE@fI!QeO8@ z>jf4zk805=;b&j=_R!M`$#8v|q}qxkXrziQ-=MxoE?Eq9kD#BLeUy%S27v{ZP3yIc zj4%u#j@o(iqpJ~bP%?|5O`1!xAz|SgXQ;m;bF(1wt5()1F7Ex?RR2G$|9j#6efl@@ z?^f7N-){;PoXZ`B9T?dnw-sc0{_^lofF0NoAYCcvAnKnAUvUQd3un7f_Px1(3zHpf ofWZ5m^merDF5Mk1-%5))r8_}mjRNs)zXEagvmCoq{M&bb0_&*tS^xk5 literal 0 HcmV?d00001 diff --git a/test/assets/simpleIndexWithCorruptedEverything.jar b/test/assets/simpleIndexWithCorruptedEverything.jar new file mode 100644 index 0000000000000000000000000000000000000000..cca7b96bc1356955577ceebe4b606d0489e6fdd4 GIT binary patch literal 2489 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 literal 0 HcmV?d00001 diff --git a/test/assets/simpleIndexWithCorruptedManifest.jar b/test/assets/simpleIndexWithCorruptedManifest.jar new file mode 100644 index 0000000000000000000000000000000000000000..d8b7b70b702f8bf0a7f49c55b62af68fbac8767f GIT binary patch literal 2384 zcmZ{m2{=@HAIFbn7+FfTaxq*QvWzVTQB*U<7-YSc(T%~7r3P8bl6p-|L?W_Wl_hVs zFnEzAQO1n1hK$s0Y-3Gmt{Cp{K971m_dVzN|DSW7bAI3F_dVzL|9$>8C>~yM004u5 z%VpVTSn|cw(EtF%afUb`1E3N1W*X*JNKLevl{pe&XAeUo9qa`Fo_x>+yFWN1G+Yqi z;$7tefSqX>O{G|(G+@2LC=FE_wY$nzYe4tY1RiFARyRlYhCb&N$e2CcmL;u<`%CHw zbShufU`k42TpR_~aKn=$e7_Og*-cr>oi)ydrq) zYNEQzGA-fDm4py7c%>9Ayz;G5G+ST`&Aa*=OY7qxZTvKGt`<06)Cgm|2?H z+nqiKvqJ`Sbz8S;9eT60p2FU5GV>((onL_fK^V!qrl6qE(k}kZ!rjPdy1rnc-02hc z^L(9g?jkn}SvSIsi7S0^EaioY$jx@wRvd(7V`y}quQ`xM7@b}9pHf--ls3q+{|B07 zr{yMTG=Y7iJcZE4h!1=H*vHJU!}oiX8A3efgf1Rl<>v%2)4tieOhi9mZA~dLo3+}d zSBGbqMIVIYW$)|VtUvLLAqe5K3*|NM8ULghqrRz?@@0O#6AW`1D0hzhN{GwDt$?eW znqv0Y@5_@IiQxu-eLMgl!TAKczjD{Ut(}=J&coZ2G2pk1Tc=SvXr#w?ms-2Gieh4Sxq?t6E=@OKMYzq~hfiX; zAio5w2-a#fWR;=LM|%^WWZVFsyXBlwE3d6wk#AtAsH=HguiMlrd#IB ztYwis)Yj9|*8}c6LN0l;)&aYS_4++<&Pxk7hxPNv{^r3fo64c6{L1#}%!+B%(L=Dq z(k1334PB}d)<6GQwy?l6ADkwsUjKps-zw{-xxc?9ofFy&0jUpDN=OT1lLK}q;g7lo zE+}rOn+(42dcWienYkP76 z^a9IgWI`tU*lt~5Zm6ZWUUy=z%U4x0Ut!-a&aED|Rpup?yY@fvtBeTxKG)LR>=QEc zvUb=T7k-RgIzldnx0h_Dp3Rx7?`0e)R>>M}V!et-c}wb?MP03E%!SfxHELKJkx>4FG&9u{ zC}HyX&TN#X&*U&>b2AY$Snw*C)(3hz+nV5PIVM9t$%uAGP;7sySU%2z7@)Ck6DBB1ERcz!RVcI1MycL%1q{zr%M_(>N>WWkuK!%cnevQjfPLZ6 zvy6xG9^<#k%2F6AG4(gk+b&}JX3Y2XTZA~L4=h-R&@MjC8d~&q>#b!su(pcTJegaa z0t?x(lngp8afI9PBiM9I!o=}1ARX^j&+)0IC}H(Brta(H(8jg#I;RWXN1{ zBtF`y>9*RxEb>NAp|}D{HIy42CI8*lIQ6`sPNrl(*>j0jEF_Rzrr^aB|qF%1^Z6Dq?+k}A)gf-GF5iZPj~`wz~)li6y} z43eJq?TwtRQ>ksd_|D!1zuF`k%5*uF<_{u{VHkEZdT(vM(V+)FX9rwvsvq%C)%!gN z!=$xWhNNE#X$Vn(`s(A)w-T?4g<2gwkZ!5r^X)(;!T}uo98G#zXn~6;kzThrP$1Qj zte)bIBvrk-uYcT;Ql=#8Juf*a^H@(Ar#EQs^+6DU@Gr$D+EyOS2;dW;LFtMSL9^JJ zD=DFQ{Rp3UHN(0bHrXwm(ZAwFhs~BJC9ya4b>t=|Cayq~`U!@f&!$d4NK3!+K4fZb zAxYC?a*Th!QKoF;y#ROj&~E>k@7mr%5JGk>|MD8%P^8f0sve^xqaqsIkcUVRN_30% zE@fC!lHU!?8Uz+Ljp=k#!q30$?deV}B*P79QW`8N&}b!Fv0ihTT(TT`F{1m-e1014 z6$BPoHfzv4I!ZT&IO*mtj;%$!N69XSHfpcPg@lD~oTL7U%*li(u36ilxVYtb{vYZO z?W{Tu#sSie?aN(S{15m+{{{aZ=x-~FbG8fHn}~k`?~e4&MEzNLmqT{Qy$XBT^+SQe zNpUx~T?G!wewO&BX7WQKiuWgp?bfn4bZ=|<5&E1Hy4z@MP$0hTM>e literal 0 HcmV?d00001 diff --git a/test/assets/simpleIndexWithCorruptedSignature.jar b/test/assets/simpleIndexWithCorruptedSignature.jar new file mode 100644 index 0000000000000000000000000000000000000000..b198ab60f4d9f8f3e278b1cbdea6d644e90787b0 GIT binary patch literal 2384 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