author | Matthew Shyu <matthew.shyu@amlogic.com> | 2017-08-11 04:42:20 (GMT) |
---|---|---|
committer | Matthew Shyu <matthew.shyu@amlogic.com> | 2017-08-16 04:15:45 (GMT) |
commit | 3f90827728a04024e1e01e8cbe9da15ac50b72d0 (patch) | |
tree | 63b2da38895bce2d5225debd3a3221dec98c2604 | |
parent | a48c2fbe733c193ba688aa23f4b16d96a93843bb (diff) | |
download | keymaster-3f90827728a04024e1e01e8cbe9da15ac50b72d0.zip keymaster-3f90827728a04024e1e01e8cbe9da15ac50b72d0.tar.gz keymaster-3f90827728a04024e1e01e8cbe9da15ac50b72d0.tar.bz2 |
Initial version of Keymaster 2 HAL and fix keymaster tests and vts tests
Change-Id: I124a6b9a36cfd9e680f3ca301295c85f72f7e209
33 files changed, 18935 insertions, 0 deletions
diff --git a/8efb1e1c-37e5-4326-a5d68c33726c7d57.ta b/8efb1e1c-37e5-4326-a5d68c33726c7d57.ta new file mode 100644 index 0000000..d5cdc39 --- a/dev/null +++ b/8efb1e1c-37e5-4326-a5d68c33726c7d57.ta @@ -0,0 +1,6857 @@ +HSTO + +!>4gpzG?O."ELF + + +vetv@`DAFaDAFataEv!etA +tv@`DAFaDAFataEvAet! +tEvet! +PV!FPaNXAB\!HPdJTdAFFfaH@LT!NJF^!BZFaDABb!Fa@DAB!@H\B!@TNRfZFaB!@DAF`D@@RVFaZ\HB!LJTB\NADA +RB~a +|! +vNLNaJAFaDAH\A@zHrA@\AHt +xxAp!pFPNXNaJAFaDAH +^TPZ\aRXaPV=@FJ@B(LLHNHhB!DDANFaHԁJޡ +z@B, +~@DA@B!B(Jԡ +tEvetavA@`DAFaDAFatEv!et +tEvaetvA@`DAFaDAFatEvet! +tEvaetv@`DAFaDAFatEvAet! +p +
+
+ +
+
+ +
+Bit-sliced AES for NEON, CRYPTOGAMS by <appro@openssl.org> +vetv@`DAFaDAFataEv!etA +tv@`DAFaDAFataEvAet! +tEvet! +\PaT +PV^aZXaZ^ARaZ!NXaBTAJV!DXdLPdAFFfaH@FP!NJNR!J\FaDABb!Fa@DAB!@DVB!HPBZn\FaB!@DAF`D@@RVFaZ\HB!LLPJVNADAZJ~a|vNLNaJAFaDAH +ppaNXBTNaJAFaDAHT@zAHr@THtANLNADARB~a|!vxxp!pAP\!P^ +TVAZaZV=_@B, +~@DA@B!B(J֡ +tEvetAva@`DAFaDAFatEv!et +tEvAetva@`DAFaDAFatEvet! +tEvAetv@`DAFaDAFatEvaet! +p +|
J
j
2 +*݀
*lFUF + + + +P +Q +~
Q + +**`
*r!
*#`
Jt
*`
jv
`
xa
j*`
z
`|A
JP +-* +>рP +Ң +ЁB!ZrH@*DAZ'
+th@JЁFaZ'
* +'
+z$|
F~hFP``B + Rp +B!ZrH@*ЁDAZ'
+ +z$|
FhF``B + +z
FhF_``B + +p +N +` +0 + +RFF-/ + +#Fb Ш & +hF +RFF{-/ + +#F# +" +ЁB!ZrH@*DAZ'
+th@JЁFaZ'
* +'
+z$|
F~hF``B + Rp +B!ZrH@*ЁDAZ'
+ +z$|
FhF + +z
FhF``B + +r +P +` +2 + +FRFF-/ + +#F*Fb ;ВZp(B!'
+hF +RFF-/ + +FF +hF +RFm-/ + +#F# + + +N\ +N +NKN\(@NlN|?m
+# +nB
hl88 P`P"RbR! + +zl
|
B~l
@+IB!+BDA
Fa
&(h +N +N\ +N +NKN\{NlN|?2 +A +B +«@ +z
|
B~
x
M
+HBb +zl
|
~l
@
BB!
DA
FaN
N
B8Н + $ +/ 6$=&i''NͲuu t,,X.4-6nnZZ[RRM;;vaַγ}{))R>q//^SShѹ + +II +l$$H\\]nӽשּׁCbbĨ917Ӌyy2CȋY77nmmڌdձNN੩IllVV%ϯeeʎzz鮮Gպoxxo%%Jr..\$8WǴsQƗ#|ݡtt!>KKܽa
ppB>>|ĵqffHHaa_55jWWйiX':'8볘+3"iip٩3-"< I·UUx((PzߥY
ڿe1BBhhAA)w--Z˰{TTֻm:,c|w{ko0g+vʂ}YGԢr&6?4q1#'u ,nZR;ֳ)/S +I$\Ӭby7mNlVezx%.tKp>fHa5WiَU(ߌ
BhA-T + +'@G(P)`) +] + +vOeGP(p Ee EEVKE % +vOOeGP(p Ee EEVKE % +vOOeGP(p Ee EEVKE % +|B| +!\hT[:.6$g +WҖO aiKwZ +*C"<
Nj-ȩWLuݙ`&r\;fD4~[v)C#hc1cB@" Ƅ}$J=2m)K/0R
wl+pH"dGČ?,}V3"NI8ʌ6Ԙρ(z&ڤ?:,
xP_jbF~Tؐ^9.Â]|i-o%;ȧ}nc{; x&Yn쨚Oen~ϼ!ٛ6oJ |)11#?*0f57NtʂАا3JAP/MvMCTMўjL,QeF^]5st.AZgRے3VGmaךz7Y<'5a<GzYҜ?sUy7sS[_o=߆Dx>h,4$8_@r%⼋I<(A
q9ؐVda{p2t\lHBWR j068@|9/4CDT{2#=LBN.f($v[Im%rdhԤ\]elpHP^FWث +XE,?k:AOgst"57unGq)ʼnobV>Ky xZݨ31Y'_`QJ
-zɜ;M*<Sa+~w&icU!}-_jFF +j +ap x +bx AGB(p F +c x@ + +0 +N +< +`jIYF, +B +GL`, +"* + +"* # + +" + +"J 0C*" +"0SCC*" +"CPAJ/ +"J 0C*"@CC +"0SBCC*"@CC +"BCPAJ/ + cPErPEBggg' p`_ + +B'p@`P `p0 +f + +n"*c +`(@**g,.^ +`(*,@.^ +g`Vbb##bCC*g``##`CC^0 R^`1bb##bCC^!F +g`PR +AD*g
T$
V!&
JAAf*0 + +g`Vb##bCC*g`##`CCb##bCCh##hCC +R +!B&
*A +&
+$cPE +g`V""##"CC*g #
J \, CC
j \!,""
j`p"C#\Al((^A(##^a**aF9*##!:,,#8Ͽ,##% R...#XA +g
JZa`
jaF*g
jA* . + +g`V""##*g ##""##J ((##j **##^A,,##^a..# +j +O +DN +O +SkO +DN +*}mJ#BjÊ㪭¥ "B,\b.^ǂ bd!fAha:jJ +Ȭ¬"} mBbÂ㢭"B,\b.^ǂ bd!fAha:jJ< +oFF= + +?F +"B<
bǂ>J&"B}bmJâѬ=ȭ +"Bb>悰ǢpJ&"Bb}mJǬѬ= +"B +Bb}¢m٬JǬ=" +Bb Ƣr( tHJBf*b}جm٬J"=B +bł@墭tH@"vhJbfJլ}جmJ"B=b +Ţ`vh`"Bx麗Jfjլ}m"JBb=Ă +x煮"Bbz﨨Jf튬}"mBJbmĢ!"zBb<*J
+ +"f +Bjb6¢¬j"BbƢG*Bf*bj6¬"jBbł墭"GJbfJj6¬"BjbŢ"BGjfjj6"BbjĂ䢭"BbGfj6"BbĢmǭ!
+"BbG TAGVaGBG &ffBf
B
B= +
B
BF +Ȱf= +fBf> +=Ȱ? +p=qr(=s8!tH=(uXAvh=Hwxax=hyz={&¸=ч? + +w +ɐ +g +OD +NWDQ +f +ND +NVDQ +e +MD +NUDQ +d +LD +NTDQ +c +KD +NSDFљQ +g +OD +NWD<4 + +OyfyN +ND +VD<4 + +OyeyN +MD +UD<4 + +OydyN +LD +TD<4 + +OycyN +KD +SD + +OygyN +ODWD<4 + +OyfyN +NDVD<4 + +OyeyN +MDUD<4 + +OydyN +LDTD<4 + +OycyN +KDSDFo<4 + +OygyN +ODWD<4 + +OyfyN +NDVD<4 + +OyeyN +MDUD<4 + +OydyN +LDTD<4 + +OycyN +KDSDF[< + +dlHL*LJ +ODflgn +O_D@% +NDHԁHf +L@O^D$ +MDhxe +Oz]D# +zLD@d@ +O\DD(' +KD`c +O[DB!& +ODHցHg +LO_D% +NDh(x$f +Oz^D$ +zMDB! eB! +O]DFH# +LDb$d +O\DDA' +KDH(Hc +LO[D& +ODhH,xDg +Oz_D% +zNDDA0fDA +O^D`h$ +MDd4e +O]DFa# +LDH8Hd +LO\D' +KDhh<xdc +Oz[D& +zODFa +O_D% +ND +Of^D$ +HЁMDx +Ox]D# +LDd +O\D' +KDc +O[D +ODr!gT!O_D`l +NDHҁx fOL^D +x%MDeO]D +LD dO\DB +KD$tAcVAO[Dbl +ODHԁ(x@gOL_D +xEND,fO^D +MD0eO]DD +LD4vadpaO\Ddl +KDHց8x`cOL[D +xeOD<gO_D +ND +MD@e@O]Dfl +LDHx +xKDcO[D +ODgO_D` +NDB!fB!O^D`쨇 +MDHx eOL]D +x%LDdO\D +KD cO[DOD +$DAgDAWDbO_DHND +x@(fLVDxEO^DMD +,eUDO]DLD +0dTDO\DKD +4FacFaSDdO[DHOD +x`8gLWDxeO_DND +<fVDO^DMD + + +x +gWDO_DND +fVDO^DMD +r!eT!UD`lO]DHҁLD +x dLTDx%O\DKD +cSDO[DOD + gWDO_DBND +$tAfVAVDblO^DHԁMD +x@(eLUDxEO]DLD +,dTDO\DKD +0cSDO[DD +OD4vagpaO_Ddl +NDHց8x`fOL^D +xeMD<eO]D +LD +KDL@@9!
!
BcO[D + +NDfO^D +MDeO]D +LD`lL +dO\D +KDcO[D +ODgO_D +ND fO^D@ +MDbl($L*eO]D +LD(dO\D +KD,cO[D +OD0gO_D` +NDdlH4LJfO^D +MD8eO]D +LD<dO\D +KDcO[D +( +(pG +'8!.m,M
8STs +e +jv.,r迢KfpK£Ql$օ5pjl7LwH'49JNOʜ[o.htocxxȄnjlPxq +D + DQ+4P_DwD@^;D +D DQ+;PVD + +vD@^ˑD D DQ+:PMD uD@^;DD DQ+ +9PDD +tD@^DgD DQ+ 8PD {D@^;DD DQ+7PDzfD@^D +eD DQ+6PDyD@^;D D DQ+5PDxdD@^˓D +D + DQ+4P_DwD@^;D +D DQ+;PVD + +vD@^ˑD + D DQ+:PMD uD@^;DD DQ+ +9PDD +tD@^DgD DQ+ 8PD {D@^;D
D DQ+7PDzfD@^D +eD DQ+6PDyD@^;D D D5PDOdDOqL@L +D^˓D +D + D4P_DODOqC@C +DwD@ +D^;D +D D + +ODOqL@L +D^ˑD D D:PMD ODOqC@C +D^;DD D +9PDD +ODOqL@L +D^DgD D 8PD ODOqC@C +D^;DD D7PDOfDOqL@L +D^D +eD D6PDODOqC@C +D^;D D D 5PDOdDOqL@L +D^˓D +D + D +4P_DODOqC@C +D^;D +D D;PVD + +ODOqL@L +,DvbD@ +D^ˑD + D D :PMD ODOqC@C +D^;DD D
+ +9PDD +ODOqL@L +D^DgD D 8PD ODOqC@C +D^;D
D D7PDOfDOqL@L +D^D +eD D +D^;D D D+5PDdDhZhDhDifDDiDiDHDDaE~v +!
*!
J!
jn +n*nJnj +dHA*fhAJAj@ +xF$dDLp@ + bp 4PDpEp`_DB!Dpe wDB!C +;P bDIVD + +DIvD )L :PDIMD n +DuID!)C ` +9PDDDA + +DDt@$DLp@ "b( p 8PDpEp`D B!Dpe{DB!C 7P"b(DIDDIzfD")( +L 6PDIDn +DyID #)8C `5PDDA +FD +xB$dDLp@ +$bHp 4PDpE p`_DB!Dpe wDB!C +;P$bHD +IVD + +DIvD$)HL :PDIMD n +DuID%)XC ` +9PDDDA + +@DtD$DLp@ &bh p 8PDpE
p`D B!Dpe{DB!C 7P&bhDIDDIzfD&)h +L 6PDIDn +DyID ')xC `5PD + +!
*!
J!
jiFD +xdDn +L + +;PDVD + +DvDL :PDMD DuDC +9PDDD +A +DtDn +L 8PD`D D{DC 7PDDDzfD +L 6PDDDyD C 5PDDA +D +xdDn +L +@4PD` _DD wDC +;PD +VD + +DvDL :PDMD DuDC +9PDDD +A +DtDn +L ` 8PD`
D D{DC 7PDDDzfD +L 6PDDDyD C 5PDDA +hdDhhDieDDiDiDBKDB[DBkDB{ +GoQcpn +g))/F +'&&\8!.*Zm,M߳
8ScTs +ew< +jvG.;5,rdL迢0BKfpK0TQlReU$* qW5ѻ2pjҸSAQl7LwH'Hᵼ4cZų9ˊAJNscwOʜ[o.h]t`/CocxrxȄ9dnj(c#齂lPyƲ+SrxqƜa&>'!Ǹ}xnO}orgȢ}c +
?G5q}#w($@{2 +<L
gCB>˾L*~e)Y:o_XGJDla +KhQK$O9O:I8J<IJ9:X)W*YZ (D +,0D4 +$ + + + D + DHNOyOz +yzEiFj D +E +F +E FF?c.OYPOZTst#$ +c dJcOIOJL9K:\y[z +xi| D +ĠD D +O9O:I8J<IJ9:X)W*YZ (D +,0D4 +$ + + + D + DHNOyOz +yzEiFj D +E +F +E FF!. + +D F + +D + $(, bH +$(D,
048< 0F + +48D<
} ~ +ISJ}兩{視|FHQ{טּPEQq~!ͷuXcaIRJ}露{視|EHA{טּWDAp~!tHc`IQJ}{視|DH1{טּVC1wx~!s8cg
IPJ}{視|CH!{טּUB!vh~!r(cfIWJ}{視|BH{טּTAuX~!qceIVJ}{視|AH{טּS@tH~OހޠpޅBޥNN0nJN0lN0ncdIUJ}笠{視|@Hq{טּRGqs8~wxccITJ}隸{視|GHa{טּQFar(~ЀРvhЅDХNN2n(LN2l(N2n(cbISJ}兩{視|FHQ{טּPEQq~uXcaIRJ}露{視|EHA{טּWDAp~ҀҠtH҅FҥNN4nHNN4lHN4nHc`IQJ}{視|DH1{טּVC1wx~s8cgIPJ}{視|CH!{טּUB!vh~ԀԠr(ԅHԥNN6nh@N6lhN6nhcfIWJ}{視|BH{טּTAuX~qceIVJ}{視|AH{טּS@tH~ր֠pօJ֥NN8nBN8lN8ncdIUJ}笠{視|@Hq{טּRGqs8~wxccITJ}隸{視|GHa{טּQFar(~ؠvhLإNN:nDN:lN:ncbISJ}兩{視|FHQ{טּPEQq~uXcaIRJ}露{視|EHA{טּWDAp~ڀڠtHڅNڥNN<nFN<lN<nc`IQJ}{視|DH1{טּVC1wx~s8cgIPJ}{視|CH!{טּUB!vh~܀ܠr(܅@ܥNN>nHN>lN>ncfIWJ}{視|BH{טּTAuX~qceIVJ}{視|AH{טּS@tH~Lppr(tHvh s~xpGSHA512 block transform for ARMv4/NEON, CRYPTOGAMS by <appro@openssl.org> + + 0S͂aQna +be` +b\A +@HPa!@!BN.D(TA@r!t!&NA#1 t@H&ADt + +"n/J +V!BaFa +0 Bx¨th:@zhvvh8Hth<B|jH4h:Bth>@~hvh<jh6@vpp jH4h>z(rк2l8ń0 + P +- + P +0 `- +"-*"G"- +-*G!` 2& Q@$! +$t'%G&!Fg'RA@ D!B @EAD PFaF `Gt +B&-&-D -D NH*N*-JH"- +"-JFH"- +F"G".`@P/ +"-*$-J%!-j$-%RaTš$V%X%YgPihP . +$-*$G$@-j$ +B'./L HHHHHH +-/JB)./*./ +B -/Jb -/)./bH'./b&./b&./#./",((((((̢ȣȧȦȨ +-/*bHH((Ȣȣ%./*b,/jbȢ!./j"ȣ -/*b*./Jb&./b(fpfzȮH>F~(rrH0j:H<f|jH4H>ftpp(rN<HttN(2 `@fr jH4@0 +"-*$B -*"-J$D("PG"g$FH$- +-*G `@P`- +"-*$BH B -*"-j$F"F("g"$J&Jh&-J- +--*g +$-*$G$N-j$ +B'./L HHHHHH +-/JB)./*./ +B -/Jb -/)./bH'./b&./b&./#./",((((((̢ȣȧȦȨ +-/*bHH((Ȣȣ%./*b,/jbȢ!./j"ȣ -/*b*./Jb&./b(fpfzȮH>F~(rrH0j:H<f|jH4H>ftpp(rN<HttN(2.`@fr jH4@0 +"-*$-J%!-j$-%RaTš$V%X%YgPihP . +"-*$B -*"-J$D("^G"g$FH$- +-*G0 @- +$-*$G$N-j$ +B'./L HHHHHH +-/JB)./*./ +B -/Jb -/)./bH'./b&./b&./#./",((((((̢ȣȧȦȨ +-/*bHH((Ȣȣ%./*b,/jbȢ!./j"ȣ -/*b*./Jb&./b(fpfzȮH>F~(rrH0j:H<f|jH4H>ftpp(rN<HttN(2 @fr jH4@0 +!-*!G!- +-*G +P +P.N + +&-*&G&- +-*G +n~S +P)fJDbdLbb&`)(
+ȫ0Ȭ0и0ȠȡȮ +ȯ0ȭ0 `G⇨f" +pg&h`h@kh
о + RaphpF0`aFFh<N6p`R(rsLh6pXwXuy)H44`8s`F`R&:a +P)fJDbdLbb&`)(
+ȫ0Ȭ0и0ȠȡȮ +ȯ0ȭ0 E⇨b" +pg"h h@kh
о + RaphpF0`aFFh<N6p`R(rsLh6pXwXuy)H44 8s B`R&:a + @- +"-*"G"- +-*G +"-*"G"- +-*G +K˼ "B0-Bü@<CDPMDż`\EFpmFǼ|GHHɼIJJA-#39FFYSlsy +* 0@P`p +`-*`G` + /*0/J`/jp//@/jAP/A/A/A@ +!
*!p /J"` /j" +"
*! ' `86XDD(`|G0 /J"|' /*"Qg / +" +b8 A@ +NHx 0C +0 +@
*@G@ + + +ol@j@O4wS'p~@S'p~@'7BS'pr~@S"pvS&p@6S&`z@r@&6DS&`tS$@r@b@ooT@@o@7oe@{Db@wO2S'p~@S'p~@'7ES'puS%P~@n@uS%Pn@@5S%Pn@%5BS%PrS" n@
oV@Jou@r@O2wS'p|@S'p|@'7ES'pu|@S%ptS$p@4S$@}@e@$4BS$@rS" e@nU@nl@j@O2wS'p~@S'p~@'7DS'ptS$@~@f@tS$@f@@4S$@f@$4BS$@rS" f@nV@Jnt@r@O2wS'p}@S'p}@'7DS'ptS$@}@e@tS$@e@@4S$@e@$4BS$@rS" e@mU@ml@j@O2wS'p~@S'p~@'7DS'ptS$@~@f@tS$@f@@4S$@f@$4BS$@rS" f@mV@Jmt@r@O2wS'p}@S'p}@'7DS'ptS$@}@e@tS$@e@@4S$@e@$4BS$@rS" e@lU@ll@j@O2wS'p~@S'p~@'7DS'ptS$@~@f@tS$@f@@4S$@f@$4BS$@rS" f@lV@Jlt@r@O2wS'p}@S'p}@'7DS'ptS$@}@e@tS$@e@@4S$@e@$4BS$@rS" e@kU@kl@j@O2wS'p~@S'p~@'7DS'ptS$@~@f@tS$@f@@4S$@f@$4BS$@rS" f@kV@Jkt@r@O2wS'p}@S'p}@'7DS'ptS$@}@e@tS$@e@@4S$@e@$4BS$@rS" e@jU@jl@j@O2wS'p~@S'p~@'7DS'ptS$@~@f@tS$@f@@4S$@f@$4BS$@rS" f@jV@Jjt@r@O2wS'p}@S'p}@'7DS'ptS$@}@e@tS$@e@@4S$@e@$4BS$@rS" e@iU@il@j@O2wS'p~@S'p~@'7DS'ptS$@~@f@tS$@f@@4S$@f@$4BS$@rS" f@iV@Jit@r@O2wS'p}@S'p}@'7DS'ptS$@}@e@tS$@e@@4S$@e@$4BS$@rS" e@hU@hl@j@O4wS'p~@S'p~@'7BS'pr~@S"pvS&p@6S&`z@r@&6DS&`tS$@r@b@hIhT@Q@O1OvS&`n@S%p%5Dt~@S%pS$@~@f@tS$@f@@4S$@f@$4AS$@qS!0f@^@OVU4D"T@"33Z@AK@A2Q@`C` +ol@j@O4wS'p~@S'p~@'7BS'pr~@S"pvS&p@6S&`z@r@&6DS&`tS$@r@b@ooT@@o6oe@{Db@wO2S'p~@S'p~@'7ES'puS%P~@n@uS%Pn@@5S%Pn@%5BS%PrS" n@
oV@Jou@r@O2wS'p|@S'p|@'7ES'pu|@S%ptS$p@4S$@}@e@$4BS$@rS" e@nU@nl@j@O2wS'p~@S'p~@'7DS'ptS$@~@f@tS$@f@@4S$@f@$4BS$@rS" f@nV@Jnt@r@O2wS'p}@S'p}@'7DS'ptS$@}@e@tS$@e@@4S$@e@$4BS$@rS" e@mU@ml@j@O2wS'p~@S'p~@'7DS'ptS$@~@f@tS$@f@@4S$@f@$4BS$@rS" f@mV@Jmt@r@O2wS'p}@S'p}@'7DS'ptS$@}@e@tS$@e@@4S$@e@$4BS$@rS" e@lU@ll@j@O2wS'p~@S'p~@'7DS'ptS$@~@f@tS$@f@@4S$@f@$4BS$@rS" f@lV@Jlt@r@O2wS'p}@S'p}@'7DS'ptS$@}@e@tS$@e@@4S$@e@$4BS$@rS" e@kU@kl@j@O2wS'p~@S'p~@'7DS'ptS$@~@f@tS$@f@@4S$@f@$4BS$@rS" f@kV@Jkt@r@O2wS'p}@S'p}@'7DS'ptS$@}@e@tS$@e@@4S$@e@$4BS$@rS" e@jU@jl@j@O2wS'p~@S'p~@'7DS'ptS$@~@f@tS$@f@@4S$@f@$4BS$@rS" f@jV@Jjt@r@O2wS'p}@S'p}@'7DS'ptS$@}@e@tS$@e@@4S$@e@$4BS$@rS" e@iU@il@j@O2wS'p~@S'p~@'7DS'ptS$@~@f@tS$@f@@4S$@f@$4BS$@rS" f@iV@Jit@r@O2wS'p}@S'p}@'7DS'ptS$@}@e@tS$@e@@4S$@e@$4BS$@rS" e@hU@hl@j@O4wS'p~@S'p~@'7BS'pr~@S"pvS&p@6S&`z@r@&6DS&`tS$@r@b@hIhT@Q@O1Ov`S&`u@S&`u@&6DS&`tu@S$`uS%`@5S%Pt@l@%5AS%PqS!l@OC` + + +`ipG +`CpGYlpGO qDh F< F@Y_OqDh F< F@YS8OqhF(4p<xBн8@YA8{O-O +wO + + +Cv/ + +E#"C+CE k`#B`*`` + +P + +OG|OwO +w' +E&C/CEt@}@d + +JzD JzD JzD " " pG +JzD JzD JzD " " pG +JzD JzD JzD @" p" pG +JzD JzD JzD +JzD8! JzD<!JzD@!@"D!\"H!pG +JzDX! JzD\!JzD`!@"d!\"h!pG +K"{D2K{D2K{D2K{D2 +K"{D2K{D2K{D3K{D3 +KzD{D|%"%% +ZCҲ8PF J@ " B c"0FZFF6QF"F<Ѹk<FS۲1F"; +i@E +Os + +FFR{<xFCF +(FM +hh +` +;QlXB p: +_# +I{DxDcyDRYRk|l< +hhBPBPApG +Kh +E +6AF0F"FW?I +D`Eh.Fh + +2EF@"0FFD; F1FJF +F3FR=0FCF +#h:!S"=)@C" F !FF Fp@ p8FFHHh1 F!F*F8@} 8 +h +h +h`b +Њh,`h<`13 + gF` hdFhENhE,FWh + E, + E (3O:O + hMh4 + (6O:O + Thh4 + O:O + hi(3 + E (3O:O +Lh [4 + O +(6Wh + (6KihO:O +Li v4 + O +(3i + ENhWiO:O + hi(3 + E (3O:O +Lh [4 + O +(6h + EKihO:O + iWh(6 + (6ihO:O +i v4 + O +(3Wi + EhiO:O + Nhi(3 + E (3O:O +h [4 + O +(6h + (6ihO:O +i v4 + O +(3i + E (3O:O +Li [4 + (6O:O + ii4 + (3O + gF` hdFhENhE,FWh + E, + E (3O:O + hMh4 + (6O:O + hh4 + (3O +ORBFRF F +FAF3F# +/JF F +BF
IFSF F + + + +*ʹƹ +/+ + + +OCZ[F
O| + +zFQF*F FYF"F[DF # ++F6;YF ++F' +0F +0F +ZF,QF + +(6# +(6# +(7# +(7#i +(7# +(7#i +(7# +(7# ++)F2FSF +9F +Fah*CC + +kK + + + +I @FIF' + FQFq + +3c`B!F8F$ +*KhBE$8F:8FqF +H# +Yp>, +Gp_P +ù +ڍ# + +C% ch` + + + h0FS@` + +: +
{ + +Z +(F)Fw + F!Fb(F)F]ȱ7+F%FF#F,FFkh +b +HF)F:F#F +Os +kh+hh +:^Chch";#hhC##hhO3jh +*hh(FB)F"F;FvB(#F,FFo8F)0Fi +# + +(8F9FP8F9FBFj +0FQF + +( F!FP F!FBFD +(FQF + F!F:F +ܸY ܸԿ'''' +b
+<F +F. +AF 98 + +FF +DB + +%2FF#F(F +(F:F3F +^h<@DñHF9Fk +
HF(FOH* + +E F + +FLOO +FEOl2 + + +O +z''' +K# +(F + + F0 F@RuFF hSh# +j+F:FG +8 +j + + +@# +Z +FFF# ` +#h FIF2FiCFG + + + +bppp#q +bqqq|-GF + +C + ey B +)qjppp + +jq +q +q5 +6 +9q{ppp +{qqq + p!qcp +pcq qqyUF^Fay?Bh"yG' + CyGgAxpx1xB +CxBa2yqyL,FLy6Ll +jq:?qq5 + *,;* +,;\;2,;2,;2 +,;lO# +cq;?qqF(0 +#qappp +bqqq-OFhFFPhBӮh + + CbyC ++qippp +iqqq5 +5 +3qqppp +qqqq +"p#qappp +bqqqy + +kq;?qq5 + *,;* +,;\;2,;2,;2 +,;lO# +cq;?qq0h +Kb" +H +I{DxDnsyDKKhG F +FhFC`+h#`kh˱+hif`8FP``H# +K" +HI{DxD3yDKOKa#h FhG > +0gIFRF"B1F + + +HFjn#F + +hB@# +H!F*FxD +@ +иX# +$ +9F + + FV FRO +8FL& +KA"{D/f +h`F FO,F F> +KB"{D/
+ + + +3h0FQF:$+FG +|F1$ +$F F +9F +,h9F @F!F ++FG + + FaF2F ++FG ++FG +G +QFG +J +8F - +(@0F)F#FG +, +hBhB@9@# +RFG +" +YB@FOs + +a F +QF +QF^% +% F8 F}0F + +WF + +&h + + + +: !#h F +1#h , + F1FRF+FG(#h +F3FGб#h F +F3FG(PF, + +O + + +( + +OOOOE8O( 8h"C)3nhD MF0i# +БBбBв# +E +BѮBOs +S'P'0h +F9 +KE + +d$^0S* +F +B8 +BM5U& +V@2p$1(TD?0`G(6pOtT5H3ZD9?=Fh&@G'^@:4`Or2CD>C7pOLL +,<Fg@n@8`OssL;Fl@f@dD>`Oue6F& + +?`@1Jf + + + +TD +OtT + + +RDOr2DDSD +K + +SDOssDBUD +K + +CUDtOeDTD +K + +ETDXOTDRD +K + +RD8OBDDSD +K + +SDOssDBUD +K + + UDOeDCTD +K + +ETDԢOTDRD +K + +RDOBDDSD +K + +SDOssDBUD +K + +$UDpOeDCTD +K + +ETDPOTDRD +K + +RD0OBDDSD +K + +SDOssDBUD +K + +(UDOeDCTD +K + +ETD̡OTDRD +K + + + +LD`TDOtTDJDBDDOrB D CD0KD$OssD EDMDOU D DDLDOtTDBDbDOrBDcDCD Oss (D eDMDOUD dD LDOtTDg@bD OOrBWDOCDOss_D}OEDOUgD<ODDOtTf@h`FhrBhB`h``>?
+Q R S0ciT0 +U V "W0Y +jpppch+q +jqqqh+r +jrrrh+s +jsssp +|4?G':C|BgJ}RD&@^@?}"G'>C}FgN@o@^D~~sc?G'>C~FgNfD@g@u5U?G'!>CFgN $/@4W@ `"p4?G'%>C#pFgN +FD'@_@&p$`"(-?G')>C'pFg~NND@o@*p(`sc,?G,@L+g@FlpNVDu,`.p5U?G'>C/pFg$FO>/@4W@12p0`405?9G('@H3_@FhVN^D=6`4p"6F & 7C7` GfJOGD8pKD:scO II +) + + +I; +G i>O}>pUD<5U?G'G + +?p@1JgȠDTDĠ\D4DRDZD"DSD[D cDUDx]D0UDTD`\DDD%xjVp $ν|*ƇGF0FؘiD\"kqCy!Ib%@@QZ^&ǶRD̤ZD22DSD[DcDUD]DUDTD\DDDRDlZD,22DSDP[DcDUD@]DUDTD \D(DDRDZD22DSD[DcDUDأ]D$UDTD\DDD +ZD +ZD+22k[D +(DK:z[D +]]DK0 +uU[DK\D4D +KDKZDr"[DDDK:z[D +]]DK$ +uU[DK\D4D +cDJ[Ds#DDJ:z<ZD +U]DJ +uUZD\DJ 4DZD +DK{+DD}J:zBD +RxK +rRU@vKd4D +e@DDqK{+ke@SD[$lMcUDc + +RDhMRMDb ,LDcMtDMDd DD^M+ EDkCDYMcUDcBDdDRSMbDDeDtDD(dLMD+EDIMkcD}cEMc0MDR,@Mb_@utDD<Md<OV@DUD+9Mkf@eDccR<b^@.NtDdU@^Dvh[`Ehheh&`F``48?4q"am8D꾤K`Kp~('09|eVD")*C#9Y[e]O~o,CN~S*5:ӆ]/SD!7Ç
ZEogL*mpFF?+8K"8H9I{DxDcyDGG!vZ8* +Q R S0ciT0 +U V "W01 +jpppch+q +jqqqh+r +jrrrh+s +jsssp +cBqH|"qIqKxDyD{D-٥ BٵBPFF;CF3F2FBFXFG +XFBFG +$(FBFG +Y)YQ@Q*Q4,; +L +h' + + +0"C + + + +0#AJ +\Ec + J@ + + +O +E>ZF + +1F$ + + +g@ FBaAgO6n@O@ +g
# +IO0 +#@{O6 +#P@Y@# +P@Y@#P@Y@#P@Y@ + +# + +*.## +02##g 4## <gg +6## 8## +:#K +>{D;`K{D3`! +L2F +l,@C + + 8hv F1F +FK@ + @ +O +`Ehh F G` F +OODD FG"FD` + +/ &F + MFWE@F4G" | + +ђF +3A@?CEh + +@ +3KEh + +HSxh1l!*@ +#b@k@#n
@F1FJF. +F0F@,4"F"p@-GFFFFlDhC@C +jB +@C +n!FRF + +"QPOc ++!F;F:!F;Fi}" +1]4x=J@+BFF* + +"1"x +|D +p +q + + PF!F" -GF +w +َ# +# +F + + + +E@} +HFH +PFIF:F#FF(HFIF;Fo +(@k +# +# +" F)FF= +A@yEXo - F4C0B(FO + + + F + +@v!F + + +E&(FH +)-CFFFO# +B +T# +Kq"{DY2FA >`X +)-OFFFب# +B +٭# + +XF!RFx +. +# + +f@C+at@#v># +K"{DHFy*Fw ` +JC60FHF@Os +' +) ' +h`h` i` +Ci`pG i` +i`j` +XB6C0BOs +2F"F =` +FB@C# +hZOs +&+(F +!<I"yD +O + +h:w# +# +hBOs +# +@ +# +8F +j' +@[FFFFFF +# +Os +XFQF*F#F +?j' +@-GFFFF
lhB@ + +N FFFP@# + "+F FX@# + " +# +FFFOhs +H!F2FxD +I{DxD#yD@@\ +ciV [0X Y +Z "B +pchq*qjq +qhr*rjr +rhs*sjs +s#it*tjt +tpfl +I +K<@ K#aKcaKaKa#f +K8K#aKcaKaKa #f +#jb g0d e +f ">f8F1F@"Pn+ +YU6Qp.O!pp YU6Qp .O!pp +T&06p*pjp +p5n0F +# +# +!F"0F4jHF1F"++ب#3D +QFODHF + + +0 + l0l +01F + "000+@+1<0T?bhqp(php +p*qjq +q5B p<@T?bhqp(php +p*qjq +q5B +# + +F8Os +2F_ + +2F +2F +2F +2Fp +2F +2Fr + +2FP + +(FF{`(F>`Fu +2 +2x +2E + +HLxDhFE F0 +2 + +2l +2 +2P + 2 + +2( +2Z +2 - +2 +2E= +2E +2Ey +2E + + +H +3yD== Fp +M +K}D FX3@;< +M3 +K}D FX3@;< +Mq +K}D FX3@;$ +K}D FX3#`8 + +JF{DX3@,;u +@FCE!F(FC%AFF8FC$ +K FYDF(FC(FC +@FCE!F(FCAFF8FC +K FYDF(FC(FC +@FCaE!F(FCAFF8FC +K FYDGF(FC(FC +@FCE!F(FCAFF8FC +K FYDF(FC(FC +@FCE!F(FC AFF8FC +K FYDF(FC(FC +JF{DX3@4; +JF{DX3@ ; +JF{DX3@$;q +JF{DX3@$;Y +KJF{DX3`@kD +KJF{DX3`@kD +KJF{DX3`hD + +H + + + + +E7O + +HFAF:F#FCu-GFFFFC0F F+h(F +FF&K}D FX`3#`pfl +MFFy K}D F +FHxDy(F C1FF F +I +)F +"h +o( `BwF0` +K{D` ` +KB X; +LK"|D!{D F +(Fk B;h6kBuAF<2F +KFhh{D3 +KFhh{D3 +0F7(F +A8FBhF4(B)RF +BhkGF@FBF@FBF
FPFAFB8YF#`F +BhkGF@FBRF@FBSF
FPFAFBb$ +B. +PFAhkG ++h x"sZxbsx3s+` +0F)F! +)pFF h;P5 +KF{Ds`hA +KF{Ds`hA +KF{Ds`hA| +Hr"IKxDyD{D9X9jEd +I{DxD3yD909Bc +"F@F1FE+h ,` + +i`KaaabKbpGKhiH{DXhh"Exr@ +M +,hKBP;BKB +;B;B +аO<O +аO5
0F9F?40F9F?E-2hx+"غB +r3h33`0F9F?~0F9F?xh +B܋BBD ` +H)FxD F!%?"a?(F| +H +;Dh +(Fp0 + +5?EE +0F?[0F? +FO +1F:Fo +B +F<H!FxDPFL? G +KBЃ1 +O6+M +!FRF +BFKED%JBVF + + F?E FO O +KEh{D3`-(F?.(F?h-(F?(F? F8 +1F?;0F?B9F?0F?#F +# 40LN9FBFB +гB
JBAF
F08F?yEHF9F3F +tJB_tJB +#AF +#=o7?3V#(F
+#0F6F0'HoxD2M +#FлHoxD3o 0o6-? +0F>HAFo xD +H"IKxDyD{D6f6x F?! F? F?# +o+h(F1F[jGF +KF{D83E0;(F= +@F FB +F F F@WF@lF FB +sh+t3h +@ @@@o+qr F.AF +@g +@f +IFF@FF + F?(F=#?1F?!9FF"F F)>F0F?%0F? +GF +L +NM|DK~D}D0FX*FK0*FXp@˿ +8F;h1F +_+B#`o4 +#`PFO ++@<FBF>F:0+ + +uF.TF*F&0+ + +aFPFF0+ + +M F\FF +FF>7Fk8` +
(FAF"F;F[ + FZ` +FF +FF +0F+` + +L +NM|DK~D}D0FX*F-K0*FXp@% +@ @@ {O3pw + .FL9F(F>%>nF +;>U +tFP +GF +; >o(>>#o F >P >OF +MFF K}DT +L +NM|DK~D}D0FX*F9K0*FXp@1 +DFO +o +FF Fof(FB.
o8f +K + +;= +FP +GF +;o(==>Ro F +MFF K}D@ +O0`pmFksCҠmFkFH1FxD'oO0+`p p p +"F)FFȹ9hF0F:F=I"F +L0F: +*F 9cF=JF8F9 +*F6 9F<F8F9* +ܰ_@_аOѠhH"IKxDyD{D22 + + +#b +< + +F<"F;?o(&KOr%H&I{DxD33yD1`1rrF;8;7F +
bF<c<b +!cK@HI{DxDC3yD1]1oF<<o(a F; + +@ x@t@ pO3pl + +$$$$$ ++hB Fx + 8hrF5 +F +(`"`g"u" +OJ +@ + +(FFFF8s^FP# +K"%F{D9F +F +05FPK# +#C`F
Fh+܀h5i 5Y` ++ + "FH# +#c`0F +Fh!hFH# +Od ~D
)\Z,+,-, +1a``D` +O< OajD + D1 )M +K"%F{D9F +K"%F{D9F + +p$h<8SSBT:\ +#FD ;\ + +Fh!hFP@ +Xp ph3`pGhppZp + ph3`pG-NF
FFFA A +A/NE;="VE"x=cx4C#^E
cx="xCcxCx4C# F)F: +G +z# +A$A$A$ + + F +E9F(F2F +<h3` +# + ى# +ܻ'ٜ# + F!B? + + +E +O +_ + + + + B# + bJUF +:k +! +!s0( + + +h2< +@' +0F!Fhx+`g" +hhhpGhhpGi4^pGK{D`pGb +N~D0hH"F; 0h;F(Fp1 +|D#h'#%HxD: `#K{Dh<# +-ܑ)\Z*+*-* +D\0> *wRx0 /q&3B0j\!pBf W!pB`ܸO/ +O< OajD\0> /&اx0 v\#p0>B W#pB(+ + 32+ FSXBXA +E F +Fo +KA"{D`@F%`Fh1F*F;h +h|FHF# +hFF +8F@@VC +F F +O5 + +37 + +i + + +F
%@F@@# ++bѹ +F
'
8F8@3 + +*@3 + +B +hO +0FYF*F$a +FF@Os +6@D@ + +7 + +hB60sF@Os +!F0F*!F + +87 @ +F
/" + +F
&,F@@&# ++FFP@1# + +&0 +c@FF@9# +0F)F8 +KF."FKFF +?'O + + +x +y + + +!F +O3 + +8 +ZF +H< +HH<(F8E(F8OKF"8FO +{D9#hX,X +9;X< + +(F8wE `*8F1RHF1OAF (F8} + +FO +F + +@i@Ϳ ++ +9F(F +(F!F7# + K{DT3f4 + + + +8n*hch+`&ch3` +hB131Bai@ +FA3 +:/ɲ]!C%=0 +CY2&(>"!2% +bp"2` +"pcp 0`#p +2`pF! +#+T +H"IKxDyD{D+T+f0`p +F
FFF +E +F2F08 +#h&`_FRF08(F0"!DO +"+ + +O ++ ڲ*[ K@40"h2*q"`@FZFZ#50#`D+4VE + +8F @*DDUE5 +[K@#< +F,0h"R + +j FG F4F0B +# +CapG@i +CbaFF + +!F +F +NB4FF~D(F1F(4 +:FB +J8d#i0F F-AF$F
F +*ТBF8F)F +)+)).):r)/ +):):s)-Ђ) +8 +K` +F + {D\[\pCppG +" 00 ++ +|# 0 +#"!0 +",C +)')CD)܉)Ќ);)Г)6
i h +٘FC.H@.I.KxDyD{DFFh%iB*H@)I*KxDyD{Dh`iB(B5F%9F*F77h"iB`HOrIKxDyD{Dv/D@F8F +8FS0FP +# + FV"FF +x +OO + 7 %F ) +I2 +t# +H"IKxDyD{D** s` + +gDz pz`p4 :;9 +!701ɲ +!7?Fи + F1.+x-+ +p +e# +ӽ# +6"h#` +H +OHt"OIPKxDyD{D)Y)k +0FU& .F +;B#ss +HP" +IKxDyD{D)m){h.y h.v +kh2{B`l`+h"Zs +O&O&O&9 +IKxDyD{D3)F)X +JH*"JIJKxDyD{D))fxx-E%&x5CxEefyy-E%&y5CyEefzz-E%&zz5CEdXМx]x$D$x,CxDd]yy$D$y,CyDd]zz$D$z,CzDd]{{$D${,C{Dd]| |$D$|,C|Dd]} +}$D$},C}Dd]~~$D$~,C~Dd]$D$,CDc
+KHP"KIKKxDyD{D(6(H +AF" + +#Et +FF9F"(FF50F"5g0
+J# +<r " Fyx +-BbO#*F!F( +-BbO#*F!F="QF2F
o? F +# +# +5pG-OFFFFhF" +3 + +0F" +0 +k+@7# +ZF"%IFBF + +J8FQF+F +
@# + +OAs +A +T+O6s +v# +# + +0 + +O ++ SD[DOS:ZDJ + + JD( + + +O"BHѼ?''1DD?1ED?1CD?1BDDDCC`C`-GOh~'Dh$OTO +H$)? + +6O +J2 +# OU 6I5 "6Ѽ!?''1?1?1?1EBCC`C`-OFFF +xqx3x?G!C +ix+xB")yCxBbyW@C#Cy5CcIFX@'p; + qcp;p;p +cqqq4 + + +3 +,$ + qcp;p;p +cqqq; +7p0qsp;?p +psq ++xiyOKK+*yKxKkyC#IFCy5Cc +Fbq:?qq4F + + +dS@ + +<,<,<,< +,<<O# +sq;?qq-OFFFFhFOz(O2 +H"I
KxDyD{D'Q'cD4`p(Fp +Z# +VPFl` +AF:F(F +AF:F(F +AF:F(F +AF:F(F +(0$($F`06!"F46)F9 +ڣ# +k_ +a +HDZF4H
h0FRF4@
( F + +0 + + +u +Ht"IKxDyD{D'b'tD4`p(Fpt +># +gPF@-&HS"&I'KxDyD{D3''- +AF:F(F +AF:F(F +AF:F(F +AF:F(F +AF:F(F +AF:F(F +AF:F(F +AF:F(F +AF:F(F +AF:F(F +F + F<P;0(< +0 +0F>BEH@]EIEKxDyD{D +BF +FF/ +B + D$ + +FFP] +F +F7BTH"TIUKxDyD{D + + +8D F +P +phpyqÈKqCh +qChqzrCKrh +rhr{sÉKsh +shs|tCKti +titpG +pX3 +p@ypÈKpCh +pChpxqCKqh +qP;q1BpGξܼ-OFFF1B.F\F4FO{ +1F(F|=6k@` +EFH"FIGKxDyD{DB +DH"DIEKxDyD{D&&@)AH"AIAKxDyD{DrE& +B<(,0FO|AF +B(3 + I2BF@ +3.>fC +\,
"J
3
~BF
+CJT5BFj +FF +F{D +JzDx2Cx20 + +rhQU5"x0ԚB"xBzH|xDBbxB44rhQU5"x0՚B{x; +# +@I
+phAU5Q] +M4xDFXOs
+9@F!F2F@#,F +&'FO +@ !F F2K +* ; + Y\x3@F!3x4ёBBZx9 +3JFxzD2 + +z? +{T`h*th*p F*m +K"%F{D +(F!F2FF F(F| + F2G%F,F1 + + +gc#rOR`E +gg +E +#E +j-O +iiiiOii h)|I +aO)*O)JO)i$|Dab!~AI c"|BO#~CO9OXHOlOl8Ol\LG O +O,GsGsss.Ft.-tEDtuEuDuLuLIvAAvvvBwBwww + + + + + +@+# + + +, #'#####$##%#&##(#'###)##*## +## +## (-'#$%&-.(')*+, .g/#g-(g'g$gg%gg&gE +#EEtOT`E +J +OakI +# e"2@;@aaO3aO|B + +# +c*b#c jb1hF-OHhhi +%hC +X + + + + Xgg +g!gg +g +g!ggXggg +g ggg!gg +g g +O|BKO3@@ +#i@O~@CO1#@#
@cE#rOR`K +BEE#ErOR`C + +BE@O~F O|B@# e + +# +c #c $ #0FhFFz +iFv +Fr +!FF$
+hFiFiFc +F +ZFV< +F $ +JFF< +F$:F6<F $F*F&< +F1$ +F< +Fc$ +F<F1$FF< +F$ +F +F<(F +jF)0 + +X +\0h0ppl`dpp`h`t0p`lp(d`h0 +#C +##gC##C##C##C##C#I #G +gK#A +#O|JO;g +@ +a + +#I + +#gO~@@ +iO9 #4&c#`g +g gBO~H # +gg # a +gO~J O;# + c "q(!F F!*Fh!*FFm(F("Fh#!Fc3-CFF((F9F2Fx F(F9F2FPI8F!FBFN(F)F(HHFPxAPhF +F' F9F*F,(F9F*F8FiFJFHFiFJF +kFFOPjMJz +( +kFF OPkOajK4 +kFF"OPkMK +kOiCLH (# + +,g#"@+@ahA$# i +iFzD#2FhFiF +2FF& +s +F Fj F!F +jF F!F!F\(X(FT(!FF(FFF(F(=(F9>(F &(-(F)>(F&2(2F>(2F &(F
(F >(F1&((F>(Fc&2(2F>(2F1&(F(F>(F4NrF~D(F F"Fb F!F]jF F!FX(!F( +FOjF2(@2xAF "jF2('2iAF " F!FH+!FYx0 F!Fx +x'' +jF58F@6( +P7jF8FiF +8F9FJF- F?%( +P +q
cP +:iFYPFP-piF5RFhF1F +hPiFC
c +0P +piF5- F +( +#B K Bb +EhDt + g BAb + +" Br
+EIO0 +g + +DAt +#t + +g +[ FAf + +E" + $ +$E' +* +(E, +,Br +E1 + Br +E7 + 9 +<@Ap # 3 +G#g*3G.ggw +K +g +$#Cg$#&#wNC&#sgY(#C*# # 3G#g.g3A#(3GcB*g +g +2DAg$wA$I3E]&#C&# E$E#C#(#C +#sB +2*g6DgJG(ggwA3Y$#C# g6G"E$##C +#cB +2E$DEE(E$<H +E +2$DEEE$H +#C# #C +# + + +2g6D Ggg6H +A +YPA!#c#OPRA +EORTC +#c +#OPRA +E$ E +EmB + +aE$EE E$HE$E +EUB +Ui +E$E +EE$EEM#EE #E"E 3E#"EE3A#C +#sB +2$DEE +E$E +EcM3Eg]6G Eg # + +EQ$EEE$AH +EY$EE #E +E#E +# + +gG#3 +# + +DK +#J +KOPRE +Ecg##ORPC +EMDE%6gI +A!K +#A +#EEc +#A +C#K4Fa=F"G +EG D +U +K + +E$HEE +I£Q#C#r
{B"] +kB"_OBVG'A"F+F +EcF#B
KFB"_OBVG'OTREi B"k +OCWAVKG'B
FFE +kB"_OBVG'EFF cF#b
kFB"E_OBVAG'KB
OC[B"i K+OBZEFF +cOeYOTX #"#OIWH(G'OHVC FFFi g"ORXOcYFH(OIQOHPG A!{r
+kB"]TE%0F9F@NI +g%N +wC#KB2 +g +hDGg +g +w +&FK/F +@<#aDC#kb
OC[B"K+OBZI OiS + +gB"gYgPA!FFGr
+k{B"YPA! +K2F;F +gcTF#OkSOZR]FYB"A!OBPOVRG$eB"{EOBXEOCYAKI)B
FFB" +k OCYOBXI)EFF c F +#kb
F_B" +G'OBVOZRKi "gB"OkSTOCUG{E%r
+k]B"E%OBTA2F;Fgc#KB
]B"E%OBTOVRG +q CB3C{q qCCCq#[O2{ +2rsr{C3Cr3 r3;s3
C3CLSsOsO3,CLCCsOtO#StOC47FC3PCtOZOZ:t00Su3 +u3NFCCOYHC@uv +SvCA3Cv vCCMFCw#[O2OY#bww1-O_}
FF !P-FF@1#@1_1?C@_1X ""F)F`3`(`6-- "u "o"F)FLipp + + Brgp
+BArgp +`Brw +cOPOHAhL +E2#MCD +EI4E52E4#C2##2EE2E@ +#4EE4E#4EE4E
#4EEL@ +#4EE4E#4EE4E
#4EE4E#4EE4EM<<CDt7 +"#6EE6E#6EE6E
#6EE6E#6EE6E#6EE<EH +! #6EE#6E"#6EE6E
#6EE6E#6EE6E#6EE6E#6EE6EN>>[ m Cd9 +*#8EE!8E #8EE8E#"
#8EE8E#8EE8E#8EE8E#8EE8E#8EEO>EFFCt89 +$#8EE+8E*#8EE!8E
#8EE8E#"#8EE8E# +8E#DE 8EGBEb . + +#D#DC +( +#D#DC +3YD#A)E( +#D#DA D#A.E +3YD#A)E
( +#D#DA D#A.E
3YD#A)E( +#D##DA" D#A.E
3YD#A)E( +#D!#DA D#A.E3YD#A) +E( +EE +E& +E + +E)( +#&A' +#D%#DA$ D#A. +E3YD#(A) +#D'#DA& D#A."E)3 +Y#D(#DA D#AE. + D3Y##DA:E g 3D:#C +Ke0#*EORPDC +C#Ke6#6(E8EC +k8#g.ORPC +k#g0C +k +#C +E@FIFe#"EC +g +kI +#MLgC +a# +. +3G#g +3A HI0g +3G#.g +gGKgN# +6##gNCO## + +cD +K# 3 +K +K# SD. +K ı# 3 +K#,cDI (# +3I (# +3I ( +3I ( +(CDI (, +# +3(I # cDI +# +3 +K#3I + +K +J +Ei #C +O@RKC#a +#ORPC + +e#"EC +OPRA +i #ORXC + +(, + +I + +4 +I +< +I +I T +K H&E +=DKOܢEUI +E + +E +EM +K +DEE EEE E4 +H +E +pt +2KEF +K D# +C2#FE +7KKU2O +EK +U + +DK + +OPRA +#i C +k +A +E%KaOPRA +A +YPA!#c#OPRI +I +HK +kEB"OCYI)EOBXkb
FF +k B"OCYI)OBXA"F+FEc #KB
OCYB"I)OBXEFFc #kb
OCYB"I)OBXA"F+FEc #KB
OCYB"I)OBXEFFc #kb
OCYB"I)OBXA"F+F +Ec #KB
OCYB"I)OBXEFFc +#kb
OCYB"I)OBXA"F+FEc #KB
OCYB"I)OBXEFFc #kb
YB"A!OBPI "FOXW+FcG'#OiSz@FIFcC#aIEUE ` +H + +G'OBVKOkSOZRi B"YPA!RFI [Fc#OXROiSFFB"OF]OBTE%OPRA6gB"KgOCUI TOiSE%OXRgFYB"F +kEA!OBPGBFKFFcF#{r
OC[B"K+OBZEb
k +i +B"OCY F +OBXI)OZRK)FEB"OkS +OCWEkG'b
OCY +kB"gI)OBXA"F+Fc #B
KB"]OBTGE%{r
+$0CF3-C%0 &0CC-C'0#[O2s +( )0sC3-C*0; +0;,0;
C3-CG-0 .0 +CBC-C/0d00 +10-C3`pC5p20OZOZ:304`FO#60OCCCC@7080 +90 CA3C:0 ;0CCC<0_iO8OX#OXH= >0?
_}-AF?0x=FFF +p
pp
8
8"pp
c`* F$>W +c]Z +Fp)Fzz)FF(FF*p<ODDDghbe
`*x
`iF "M + +hF F +h`pG h` +i`Bh`-GFFFFF +!'H8F!! 8F!豍QF(h"3FHF! +ѣi0F +Os + +K{DhG9F*F* + +KA"{D1
+! +Ci`pG Dh` +h`h` +* +8O + +,4"\2ҲTR + + + + +P8FMJF + +тBS + + + + +iS F1F +
K + + + + + + + + + + + +F +x3 +" +"FF"FyF +,|ii"F +OG"FADki"FYxiiO"FADo`ki"FYf(h
6.@ +"8# +" +P + +"P# +" +)FF@ h %`0`(F +KF{D +ڕ# +FFFh# + +тBS + +GF8@ʿ +h?Ӕ +XFOp Fp!FOr(J F)FzD +L +и +.H".I/KxDyD{DCN1eRKaX!(HxD```` +FF QF +K(F{Dhb` + F8A +D`-OQ W; F +F*W% + F F + +!FK + +FP# +# +FOqF F +Ft!F F8 +F!ԿF Fh JhDhBh3k#GO0o +> +"^ +G F +FF(x4 +г
+рh] 븀h]|h]Os +# +# +i-Os +i@-Os +i-Os +i -Os +j +^kFOs +Ѐ+Os +K}"{Di@ +KF{D+h(F!hiGF h%` |I +"V +"yD1 +" +"yD1M +0F +# +hS# +~# +3F\#` +"d +"yD1 +" +"yD1P +1# +K"{D F +@ (`1F1Fp@ p +" +"yD19 +"G +"yD1 +KA"{D F +KA"{Dp F&9F@"@`%i(F0F` +Os +HF +Os +F +BF;BABd\AB ++Os +! +@w# +" + "yD1v +" + "yD1* +08F +h#h#+-GFO +0ZFH# +0FH# +`h`F9F0F" + + +ўH_"IKxDyD{Dl~(
@"@9$F O + +~d^$J +7p` +S +Ay<qi QIDE71qc + +Ҫ# +F H +EO + T'HFAF:F$JT +"F+F#D 2C + + 4 + +[ +K +K +K +F(F +H7"IKxDyD{Dp +FF%02F + + +H"IKxDyD{D +chS% +F +F +FF + +A+ 0pGFF +4DE +JzD#hhB +#FpGO0pG pG +#'FpGF +#ûFpGFPhLN~D0FsphH)FF 0FkhHxDe
K(F
I@m2{D +hGI0FyD FXFpF (F|F(0F:FFq !} +LF +I|D`X + I +LF +I|D`X + I +LF +I|D`X + I +LF +I|D`X + I +LF +I|D`X + I +LF +I|D`X + I +i!=FPl# + +J#h +( +( +( +JF +B=nYF0F>F# +cb#b +, ( +$ +chhcj3(F!F!!F(F!<
X4 +& +VpFP@U +!0 +)8F))L|DL|DL|DL|DI(FObyDT!F(FObN I(FObyD8@E +# ++sI"yD"F@@ +, +NDI(FyD"@I(FyD!F +FA)7:a)W:@ +O +IF +(F +!
( + +!!@Oa4 F9F Fg(FA
mi +HF!F" +#"Cp + +*& +0F + F8O's +O +(F]F8@# +Sp +YF F " +! +D +RD +#Cp +`rh +`jh +```^0F[(FX 8Fh0Fe(Fb + +` + +O3 +F +F +O3 +F +O3 +O3 +F +1FBF;F +" + "yD + + F2 FhBѿ +ݶ +I "yD 1 + +Hm"IKxDyD{D(F!F FH +(F3(FBъ +> +FIyD +FIyD +0"J +"B +0"1 + " + F +F8@ +g@F +Д# + ӕ# +PF)F ls\ +0 + +Eё
+hPF +
PFFZF + +ZF +RFgSDgf +f>O +
( +PFYF : + + +EHF!F :F$H"$I%KxDyD{Dc!:\pD T +;BKEo +4 @j# +# + +@w +" +F +` + +! + +R] + +0"f + + +"= +0"(@@ +"FP@ +" +( +" +FPOs + + FA=F(B F# + +! + 2 + + +mF( B# +KD"{D8 F +k +HFtFP@ + HF FHF9FF + FB +A +i*|J +h)|I + + + + + +FpG pGF@hh8 F +I`C` HyDxDF ` F,F +p +Kh"{D F +FFFh# + FFX# +FFrFh# +`F +"G + p + +O +Cx4B"!xbx4B"+ F +wh8FF3FYF FJFGO8NI F"yDG +(F!Fh3hi +I F"yDGf +"F. +O +Y +IFFSЃh0FBBFG +#F + +(FF1F&0F G D\D +FKh+IyD0Y +V# +FPe# +}# +F# +"$#xB +P+U+ +d=ihFX@# +@# +(FF8@3 +`D +rI *FyD F + +mJmI{DzDyD` + +`0ѫ`,a +@ +"(F#xB + F7F
Fkt(а(Ѡh)F0@hh)F0@0h)F0@P# +` +RH"RISKxDyD{D FF8# +I F$yDIyD +FhDIF;F2F FyD8FH@I2F FyD+h Fh +K"%F{Do1F + O +# +"yD3 +K"%F{D=1F +I(FyDB F ++
+PP<2O*0FiFF +OCD~3+~ؓy
/TzOCyDzsO + +A +zDzzO A Dy({/,%9,#Q{/) 9)$/OD
DuБ{.)&B/ټ9 +d! +
' + ++6 +O +O +O +FFhըI
"yD +"yD +# +]iI FZFyD@ +j +FF + +h ++h? +Fh +=<,E<$=$ +h[hhF F +hhh#h++`hQh@(`hQh@)ͰFF)0220F*FԱ##`F
)F0F9F@#h53#`0FBO0MFh+@h+@h F@l8F YFp +6HF hB0(F + +@h`Gh8F+ F9FFp(h08FK FLFXk6(hB0 F +FF +X +
+C!C + ! + +3# +K"{D6 +hhhpGpFm pchc#h۹)F`hyLB5 +5 +Ѫ# +#acas (N~D3hsHxDF0`8# +0F!FCh +`#ih f!Fff + j@0sFo +`f!F&f +- +" +6E +=
--1F"67=2xZ*-*+*0",FpZp3F-prxZpбx.)6=x609 )<3FB3F +hFYC +
+;hi`& + +j@Ā*j +E0@3kBPih;դDCB:h+hhhZX +2BU +``` h + coF + hnعaF#l FGF + + + +Ff#g cg# +# +YFPF8F0PFEPFEHFO + +S P O + QF(hF + + +EѺ + + +@s +A
F(FB@ +F +F +% f!Fi +FFFFF +.i2" + + +!F(Fqh4;`DE8F-CFFFF + +h|`0F)F`x` -AFFFFh$]F +FP (F!F:F3FA@3 +Ch``ch +[h`pFFF8 F%O5-I*FF +FIF{DXX!F@>G +FIF{DXX!F@G +FIF{DXX!F@JF +FIF{DXX!F@<F +FIF{DXX!F@HF +FIF{DXX!F@NF +FIF{DXX!F@ +~F +FIF{DXX!F@^F +FIF{DXX!F@>F +FIF{DXX!F@F +FIF{DXX!F@ʾE +FIF{DXX!F@E +FIF{DXX!F@rE +FIF{DXX!F@:&E +FIF{DXX!F@*E +FIF{DXX!F@иD +FIF{DXX!F@ND +FIF{DXX!F@.D +FIF{DXX!F@C +FIF{DXX!F@vC +FIF{DXX!F@VC +FIF{DXX!F@C +FIF{DXX!F@ +B +FIF{DXX!F@~B +FIF{DXX!F@6B +FIF{DXX!F@hA +FIF{DXX!F@ @ +FIF{DXX!F@ƾ@ +FIF{DXX!F@ؾb@ +FIF{DXX!F@ +FIF{DXX!F@? +FIF{DXX!F@"b? +FIF{DXX!F@ +FIF{DXX!F@ڽ> +HEZ(Ќ(#iC +O2F(hQFFhBF + +(hMEL8F + +(FA=F(B p# +p +)F F1FF F(F| +)F~ F1FnF FD(F|q +)F. F1F,F F(F|
+ +FXi a%d + + + + +khh`hh!F[nh`hHAFM +F F +Թ Ah +%@ F +(hO + D=xhAF + + F + DY.EY,:(F9h +9)F8FFF +h* +!F0Fv*FF8F4BF0FZB@P(FhF
F+a
*X +ѩx*xkx +IyDIyD= Fih +FFUOs +QFF FFHOs + +HFEHF )FJF{F Fb6@ +AбiA
(FG [Fx9F +-I F"yDP4%'F48x +1F`BF +]8F +DJ#F ++x@+3 +F +5phB!I FyDSh㱛h FIJF +DP# +q# +1ع@ +" +PFOs +hOs + + +Z8` + +~ +#I0FyD0 +hB,+*# +2Fh+h +(F6 +hhhpGh +hhhpGChpGsFN~D3hsHxDF0`8T# +KA"{DV(F F +M}D(h +FFF- +HFYF"@ * $K" +5 !F8ln)F048lTB + + + +I F"yD Fih 8 +zj +8F`%JzD + F*FSF +hhhpGhhpGjFAj +j +ѣ# +M +I{Dh}DyD
X(4L,K +܂(܁(6(Є(1(܉(Ћ()PEXE$jCjCjCjCjCjC +jC@jCjCsb8F
EoK8FY
+# +K {DP(F F2 + +TZp#i3#a F@hh h F@{-EFhFF0
+0$~D +7NO + +
$ + +MchCsc`!F F0 +*-F F@e + FH@o + +F F F,F Fp0FhFYF +F F,F F00FFo + + +(F + + + +O +K" +H!{DxD +K" +H!{DxD +FpGK{D`pG +K" +H@{DxD +KB K" H@{DxD +K" +HOq{DxD +K" +H\!{DxD + +K" +H@_{DxD + +KB +K" +H@ +!{DxD +K" +H@S!{DxD +K" +HOq{DxD +FFk˱gk1FjB4B(/F:Fkak8c +BDckk<[BD +1[BD1F +KB +lKB +أSB +=FFO"#:F +k)F*F +| + +>|
K"
H@{DxD +-ĕ +bib +MKB(F +i%K"HOq{DxD( +ch +FFxK"H@!{DxD( +liC +KBM(F +BC#iCE> j)`j&i9F j##afFP`j1F`FKB&iC#a KB3B3BK"HO4q{DxD( +|KBMM(F +N*h#hBGK +0F +9ch+i(F"!jFbj/i0 acikajb00BjkckB0K +jjDZ~'K"'H@!{DxDH +jjk +!kc~K"HO?q{DxD +kkFK"H@1{DxD + +%kb9F2FFK@#1H*F{DxD +q +5KB F0 +ch+(K +i[#jK +j F3&kbAF:F>FxKOXqH2F{DxD( + +00 +A{DxD +KL F +L F0 +sB;BsBѨkik +A +kKB F +>ch+K +)iZ#jK +j F_# Fb9F2F@i +ch+.K +i +j+K +k1F*FFK"H@A{DxD + +5KB F0 +Pb
LK"H@)Q{DxD + +zD + kjk(F +,J(FX#F +H +;BKB3BK"H@a{DxD +{ +H +;BKB3BK"HOa{DxD + 9`{`l{ala +H +;BK"H@Oq{DxD +LH"@aq{DxD +2H"Oa{DxD +(H"@jq{DxD + +K" +H@q{DxD +K" +H@q{DxD +`HxDA`hF +` JzDh;`3@]h +o +p +HxD + +o +lK(F +K" +H!{DxD + +ո Q +F{D +HxD + + F +t + +Y + F +F +) + F + + +F¿pF
FF!F +_ +0F!F x +H LxD K" HA!{D +[h + +a +l2 +d@VH@E2UIVKxDyD{DP, +BIKxDyD{D`O +BlH@kIlKxDyD{DB3z&.gHOrfIgKxDyD{DS,8S<AhB`H@`I`KxDyD{DC`D<D,1FD,MWK{Dh +"*I*KxDyD{DN3A F)FF +V5p +تBؑBبB3B +; +ܸ#fи*fи @X.jи0и-@_U +3h6C{j + + +`H`" + +AEq0 +" +" F<F
F " +#x( ! AqFFT
XF +;< +E +պ + +o0$ +K9 +8 + +1YE{ # +;: +q1JzD +ȿ$,($+U ++, +Jh01 +F + B FAFh +8A0F_z1F O#F{OO + +!MF + !7OE + +!FO!FK!FG +ch" +FKFFF;F +:/FF +74 + +50_( + ( +(
(а HBHApG pGA +@6KD FF +{h[B{`O6JzDx0F +B + 0\>HFQ2F1) +1 +0 +i + + +h +F F +(FF F(F!F(F!F0F!F0F7F
FhF!F!FjF+F>FɄ +? +
5@˄ + @7 +Y@ +'J#<#D@:M@ + +v1F F +!rp1t! +s/ +qbFbXFO^p'2 +$mAvAA( +18#* +Fi&YF F +? +_ +eF
@( +y +#B@K@~ +K@B@ +# + +v\E + +E `@i@ +t\ +04# +x +E|l + +F@O@ +#F@O@g{@r@ +gF@O@gp +g +gg x +@ +p@y@ +g + + + + +#`@i@ + +JF8FEE#T@]@ + + *F48FB,%,,cArb +#(gr@{@&g(#t@}@&En^ +>7FF*FF Fa F>0F FO + +*
*
:PBPApG*XBXApG +)) +.+/+:+=+?+$%\ B +hB+++@hIh@hKhpG@hIhܼO0pG ++ + +ih +G FF@-G
FFiF +xh +h
Fh +!C4( (#hC#hC#` + +F@0# +E4GFWF0F +FF1FRFj1F +AF:F(F3F +#jb#B
F7
+#Aqjb +gai +C + + + +B:R +BhR# BF@Ͽ3B +FF(#hXh#h]`( 88 +FF(#hhp#h`( 888FhiB +FoF(#hiY#ha( 888Fh + +(
( (аXBXApG pGa+A8( +ڰG +Z6:h +8X'O (F OI +8X_F +h`:`9F"F3F""?GE +6:h +JZEZF + BEBF +3FE !FXF + + +Fx1Bxp*(xxp: +JOO;K? + +&PF1O3S`d + +D; +O + GYh +O + + + + + + + + +: ? +E; +O +DEмB +*Fch + +FHhFhR<R`R,FhS`i`HiGp +R#F +O +T!8 +B +T! + Bت + + gE5T% +F +Y%:F5vPFshB +Y' +&v +OD + *F6MFW +@BF +FFF!F9FBF#FD1F +FFF!F9FBF#F1F +FFF!F9FBF#F;1F +919Y::j;;<ѐ<==>>>?W?o@ӆ@AmABFB2 2$2$3$3$4$4$5$5$6$'6$57$C7$L8$Y8$l9$R2(j2("3(}3(^4(4( +90%90::0N:0b;0s;0<0<0=0ˁ=0>0>0?0?0&@02@0GA0WA0nB0{B0C0C0D0ӂD0E0E0F0-F0JG0cG0qH0H0I0I0J0σJ0K0K0L0L0)M0?M0MN0cN0uO0O0P0P0Q0΄Q0R0R0S0'S0?T0XT0qU0U0V0V0W0҅W0X0X0Y0Y0,Z0;Z0[[0j[0\0\0]0ӆ]0^0 +I@$I@;J@YJ@qK@K@L@L@M@M@N@N@AO@jO@P@P@Q@R@R@ S@3S@HT@kT@yU@U@V@V@W@W@X@#X@R Y@Y@ Z@Z@ [@̠[@ \@\@+!]@B]@!^@^@!_@_@!`@ޡ`@""a@Za@q"b@b@"c@c@"d@d@#e@e@5#f@_f@#g@g@#h@h@%$i@Si@t$j@j@&k@?k@U&l@Шl@(m@'m@U)n@n@)o@֩o@)p@p@ +B +B'%BB'BB&
Bߦ
B&B'B;B]'B'B'!Bx'&B(+Bb+B(,B!,B +2t2tE3t~ 2x2x 3x3x 4xÉ4x 5x5x +6x/6x? +7x`7xs +8x8x +9x9x +:xԊ:x +;x;x <x<x5=xJ=x +>xR>x2| +j +{* +
p'd'_0
lb^xGf +kG| +ෑJ .<Eɋyǐ:%;$%`7 + +#ae +NQ +S zLv +c"
.I'T^jUi~wKVA\o&1m&l@PXMBeg4ѤO +qN8qc~uks) +K=c#.r!Ź(ɜ`幡̀AƘu]12D:mH +ܚ}ts1s'0]Aۅ0a(6p1Ĺ +Kџ;hd
Y`Щ#~qc88GZSwq4
+Ӑep*yLqZ{jriၑljV@9/_jwcc7 +([ow0%0nV4ERј4|qP`tT "GRb4Z''Jivj֨^R +b|}R +! +V(W&`Pqy?ʳ%dDg%gMRw4:Qm<H5gRR-:v?pO\09NA_[l{uB"XG[rgk0ZzQd |m);o 40aEW
+хRЀ;U.?gdqvZ/o4Byd8ւvÊb*}wKcWz1e + ++0C:ͳ4yJQ";tgN)܀b4h! + +!/wP[klMJȮTQwą6h3ێ^(ZD"2kr.:+^$l6'W`'_ + + + + + + + + + + + + + + + + +6J&,o])(|1 +`~zC|_cM7-X
Hzj)s*H= +A2VPDغ'9C#Uk2JV"42\!7c#L"CuZGdDՁ + +! +1 +9 += +I +W +a +c +g +o +u +{ + + + + + + + + + + + + + + + + + + + + +#)-?GQW]eo{%/1A[_amsw
!
+
-
=
?
O
U
i
y
!'/5;KWY]kqu}
%)1CGMOSY[gk!%+9=?Qisy{'-9EGY_cio
#)+17AGS_qsy}
'-7CEIOW]gim{!/3;EMYkoqu%)+7=ACI_egk} %39=EOUimou #'3A]cw{57;CIMUgqw}13EIQ[y!#-/5?MQik{}#%/17;AGOUYeks '+-3=EKOUs !#59?AKS]ciqu{}%+/=IMOmq
9IKQgu{ ' ) - 3 G M Q _ c e i w }
!!5!A!I!O!Y![!_!s!}!!!!!!!!!!!!!!!!!" """!"%"+"1"9"K"O"c"g"s"u"""""""""""""""# ##'#)#/#3#5#E#Q#S#Y#c#k################$$$$)$=$A$C$M$_$g$k$y$}$$$$$$$$$$$$$$$$$$%%%%'%1%=%C%K%O%s%%%%%%%%%%%%%%%%&&&&'&)&5&;&?&K&S&Y&e&i&o&{&&&&&&&&&&&&&&&''5'7'M'S'U'_'k'm's'w''''''''''''''((
((((!(1(=(?(I(Q([(](a(g(u((((((((((((()))!)#)?)G)])e)i)o)u))))))))))))))))***%*/*O*U*_*e*k*m*s***************+'+1+3+=+?+K+O+U+i+m+o+{++++++++++++++ ,,,#,/,5,9,A,W,Y,i,w,,,,,,,,,,,,,,,,---;-C-I-M-a-e-q-----------...
...%.-.3.7.9.?.W.[.o.y................/ ///'/)/A/E/K/M/Q/W/o/u/}///////////////0
0#0)070;0U0Y0[0g0q0y0}000000000000000001 11!1'1-191C1E1K1]1a1g1m1s11111111111111 2222)252Y2]2c2k2o2u2w2{22222222222222223%3+3/353A3G3[3_3g3k3s3y33333333333334444474E4U4W4c4i4m44444444444444 555-535;5A5Q5e5o5q5w5{5}555555555555555666#6165676;6M6O6S6Y6a6k6m6666666666667777?7E7I7O7]7a7u77777777777788!83858A8G8K8S8W8_8e8o8q8}8888888888888899#9%9)9/9=9A9M9[9k9y9}999999999999999999::::':+:1:K:Q:[:c:g:m:y::::::::::::;;;!;#;-;9;E;S;Y;_;q;{;;;;;;;;;;;;;;;;;;<
<<<<)<5<C<O<S<[<e<k<q<<<<<<<<<<<<<=
====!=-=3=7=?=C=o=s=u=y={=============> >>>>#>)>/>3>A>W>c>e>w>>>>>>>>>>>>>>>>?
?7?;?=?A?Y?_?e?g?y?}????????????@!@%@+@1@?@C@E@]@a@g@m@@@@@@@@@@@@@ AAAA!A3A5A;A?AYAeAkAwA{AAAAAAAAAAABBBB#B)B/BCBSBUB[BaBsB}BBBBBBBBBBBBBBCCC%C'C3C7C9COCWCiCCCCCCCCCCCCCCCCC DDD#D)D;D?DEDKDQDSDYDeDoDDDDDDDDDDDDDDEEE+E1EAEIESEUEaEwE}EEEEEEEE +FE{3`SNB. h'=6xJ{C^t9ۃoâ:J3L;`oJu}Yd3md5_sha1_init + + + + + + + + + + + + +UU*H
*H
*H
*H
*H
*H
*H
*H
*H
++ +++<*H
++*H
+*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
`HB`HB`HB+*H
+
+*H
*H
+`HB`HB`HB`HB`HB`HB`HB`HB
`HBUUUUUUUUU U#+UUeUdU*UU+U+UUU
*H}B +*H}B*H8+*H8+$+$*H
*H
U%++++++++7+7+7 ++7 ++7 +`HBUUU+e*H
*H
*H
*H
*H
*H
*H
+*H
+*H
+*H
+*H
+*H
+*H
*H
*H
*H
*H
*H
*H
*H
++*H
*H
*H
*H
++7*H
U)U.++0++0+0+ **H*H8*H8*H
*H
*H
*H
+*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
*H
+ ++++ ++ ++++++++++ + ++++
+++++++++++++++++++++++++ + +++++++++++++ + + + + + ++ ++ ++ ++ ++++++0+0+0+0+0+0+0+0+0+0+0 +0 ++0++U++++++++++++:X &,d &,d
UU7*H
+ +++ +UHU$U7U8*H=*H=*H=*H=*H=*H=*H=*H=*H=*H=*H=*H=+7`He`He`He`He`He`He`He`He`He)`He*`He+`He,U*H8*H8*H8 & &, &,d &,d &,d &,d &,d + &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d + &,d &,d &,d
&,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d &,d% &,d& &,d' &,d( &,d) &,d* &,d+ &,d- &,d. &,d/ &,d0 &,d1 &,d2 &,d3 &,d4 &,d5 &,d6 &,d7 &,d8U-+++++U,UAg*g* +g* +g*g* +*H
g+7+7U U+++ +*H= ++ +g+g+U +*H
`He`He( +******b*c** +*H
*H>+$+$+$+$+$+$+$+$+$ +$ ++$+$+$
+$*H
+H? + SiJJ) +A @@ 4!R +"A !@h@2l + !!IP& DA +B`! E +
@ ) 0 +@B + + + + +$ +d + + + + + +o/Dyeڜ + + + + + + + + + + + + + + + + haead_ssl3_tag_len +YG=6D^:հ5mp?LPiBl)+18{kΨ`%cfc}Ҵ#ZoAsu0RhEf;S<iliQ҄(f mrae!2Hz8u=Jo=?Wk?Jnr{[t꾜zm@I*upNtu>MfO<lwGQcT;0*u)L|m8U[#(6A&>ʜz+`Edo\ MKZ&irb>^SOsvt:MևllDr>sN=ZuY,GA馗&js[ee[0bY26RJ!^ kZ̰ҋ_;>qf(?' Z#a
-D\NxzWenqDCPgHZFHzEi 돲mvX St-SnQ<}ukjR0EQ6F?>7Ϙ^ZSw `@\⥭*k~#[
(-@L5 +&byM]1~ӡAa]Ta|IDt/z/]>)M7n(l X2o6W]v1Cyב1b<Ґ,V7{@X"y:1
+}ztFr=ܽh
q2i;xWnnE7JQOg<#hdjE2!Y|PVi{X;MFmE4͉nJ{@'+fY{935/.hS\Rw't#>..
%%99=ng^fc(Nt]wv^b<W+6.9>um:15y5&kZ$m1K
FJ+C7Ys<vx˦
y_([QBoP=!^%]7G0pNCG*b]3bV$fCh;i|կ>!1j^|EՌW_/OR|X_Q!/[j4mXKs]ė*lFBWP5<mlΰɢwk70,^_Z0Nbe+V>MϺb_r(W=W}q1옐TG\r$d
|s;UX0/bfU!%dqKvYŪgÆ%NK?D.j]SP3٨-}*? +Ҽ3bSwCf'C_U*LzyXzted0\UVE;><jRr[9 #JL]#j==}?#GqlWC3{bF}i8'o8ŮfsL!:6VudǫZ&BRCm1$$o!ۃi;kT/\wa
;>OZ)1?6ⷜҼ/=rhR%LJ`~BdrF[Yqexternal/openssl/src/crypto/dh/dh.c + + + + + + + + +*H
+*H
external/openssl/src/crypto/pkcs8/pkcs8_x509.c + + + + +%8sNext Update: + + + Revocation Date: + + + + + + + + + + + Public key OCSP hash: + + +%12s%s + + Not After : +%*s + +%*s + + + + + + + + +%*s + +%*s + + + + + + + + +%*sZone: %s, User: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +*H=DB +California10U
Mountain View10U +Google, Inc.10UAndroid0
160104124053Z
351230124053Z0v10 UUS10U +California10U +Google, Inc.10UAndroid1)0'U Android Software Attestation Key00
*H
+California10U
Mountain View10U +Google, Inc.10UAndroid0
160104123108Z
351230123108Z0c10 UUS10U +California10U
Mountain View10U +Google, Inc.10UAndroid00
*H
+*H=010 UUS10U +California10U
Mountain View10U +Google, Inc.10UAndroid1301U*Android Keystore Software Attestation Root0
160111004609Z
260108004609Z010 UUS10U +California10U +Google, Inc.10UAndroid1;09U2Android Keystore Software Attestation Intermediate0Y0*H=*H=B +*H=H +*H=010 UUS10U +California10U
Mountain View10U +Google, Inc.10UAndroid1301U*Android Keystore Software Attestation Root0
160111004350Z
360106004350Z010 UUS10U +California10U
Mountain View10U +Google, Inc.10UAndroid1301U*Android Keystore Software Attestation Root0Y0*H=*H=B +*H=G + + + + +N +V +V + + + + + + + + + + + + + + + + + + + + + + + + + +i +i + + + +n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +A +*D + + + + + + + + + + diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..3c8074b --- a/dev/null +++ b/Android.mk @@ -0,0 +1,105 @@ +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH := $(call my-dir) + +KEYMASTER_TA_BINARY := 8efb1e1c-37e5-4326-a5d68c33726c7d57 + +include $(CLEAR_VARS) +LOCAL_MODULE := keystore.amlogic +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := module.cpp \ + aml_keymaster_ipc.cpp \ + aml_keymaster_device.cpp \ + +LOCAL_C_INCLUDES := \ + system/security/keystore \ + $(LOCAL_PATH)/include \ + system/keymaster/ \ + system/keymaster/include \ + external/boringssl/include \ + vendor/amlogic/tdk/ca_export_arm/include \ + +LOCAL_CFLAGS = -fvisibility=hidden -Wall -Werror +LOCAL_CFLAGS += -DANDROID_BUILD +ifeq ($(USE_SOFT_KEYSTORE), false) +LOCAL_CFLAGS += -DUSE_HW_KEYMASTER +endif +LOCAL_SHARED_LIBRARIES := libcrypto \ + liblog \ + libkeystore_binder \ + libteec \ + libkeymaster_messages \ + libkeymaster1 \ + libteec + +LOCAL_MODULE_TAGS := optional +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_REQUIRED_MODULES := $(KEYMASTER_TA_BINARY) +include $(BUILD_SHARED_LIBRARY) + +##################################################### +# TA Library +##################################################### +include $(CLEAR_VARS) +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := $(KEYMASTER_TA_BINARY) +LOCAL_MODULE_SUFFIX := .ta +LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/teetz +LOCAL_SRC_FILES := $(LOCAL_MODULE)$(LOCAL_MODULE_SUFFIX) +include $(BUILD_PREBUILT) + + +# Unit tests for libkeymaster +include $(CLEAR_VARS) +LOCAL_MODULE := amlkeymaster_tests +LOCAL_SRC_FILES := \ + unit_test/android_keymaster_test.cpp \ + unit_test/android_keymaster_test_utils.cpp \ + unit_test/attestation_record.cpp +# unit_test/attestation_record_test.cpp \ + unit_test/authorization_set_test.cpp \ +# unit_test/android_keymaster_messages_test.cpp \ + unit_test/hkdf_test.cpp \ + unit_test/hmac_test.cpp \ + unit_test/kdf1_test.cpp \ + unit_test/kdf2_test.cpp \ + unit_test/kdf_test.cpp \ + unit_test/key_blob_test.cpp \ + unit_test/keymaster_enforcement_test.cpp + +LOCAL_C_INCLUDES := \ + external/boringssl/include \ + system/keymaster/include \ + system/keymaster \ + system/security/softkeymaster/include + +LOCAL_CFLAGS = -Wall -Werror -Wunused -DKEYMASTER_NAME_TAGS +LOCAL_CLANG_CFLAGS += -Wno-error=unused-const-variable -Wno-error=unused-private-field +# TODO(krasin): reenable coverage flags, when the new Clang toolchain is released. +# Currently, if enabled, these flags will cause an internal error in Clang. +LOCAL_CLANG_CFLAGS += -fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp +LOCAL_MODULE_TAGS := tests +LOCAL_SHARED_LIBRARIES := \ + libsoftkeymasterdevice \ + libkeymaster_messages \ + libkeymaster1 \ + libcrypto \ + libsoftkeymaster \ + libhardware + +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +include $(BUILD_NATIVE_TEST) + diff --git a/aml_keymaster_device.cpp b/aml_keymaster_device.cpp new file mode 100644 index 0000000..df8b9b9 --- a/dev/null +++ b/aml_keymaster_device.cpp @@ -0,0 +1,997 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AmlKeymaster" + +#include <assert.h> +#include <openssl/evp.h> +#include <openssl/x509.h> +#include <openssl/sha.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <fstream> +#include <iostream> +#include <inttypes.h> + +#include <algorithm> +#include <type_traits> + +#include <hardware/keymaster2.h> +#include <keymaster/authorization_set.h> +#include <log/log.h> +#include <utils/String8.h> + +#include "keymaster_ipc.h" +#include "aml_keymaster_device.h" +#include "aml_keymaster_ipc.h" + +const uint32_t RECV_BUF_SIZE = 66 * 1024; +const uint32_t SEND_BUF_SIZE = (66 * 1024 - sizeof(struct keymaster_message) - 16 /* tipc header */); + +const size_t kMaximumAttestationChallengeLength = 128; +const size_t kMaximumFinishInputLength = 64 * 1024; + +namespace keymaster { + +static keymaster_error_t translate_error(TEEC_Result err) { + switch (err) { + case TEEC_SUCCESS: + return KM_ERROR_OK; + case TEEC_ERROR_ACCESS_DENIED: + return KM_ERROR_SECURE_HW_ACCESS_DENIED; + + case TEEC_ERROR_CANCEL: + return KM_ERROR_OPERATION_CANCELLED; + + case TEEC_ERROR_NOT_IMPLEMENTED: + return KM_ERROR_UNIMPLEMENTED; + + case TEEC_ERROR_OUT_OF_MEMORY: + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + case TEEC_ERROR_BUSY: + return KM_ERROR_SECURE_HW_BUSY; + + case TEEC_ERROR_COMMUNICATION: + return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED; + + case TEEC_ERROR_SHORT_BUFFER: + return KM_ERROR_INVALID_INPUT_LENGTH; + + default: + return KM_ERROR_UNKNOWN_ERROR; + } +} + +AmlKeymasterDevice::AmlKeymasterDevice(const hw_module_t* module) { + static_assert(std::is_standard_layout<AmlKeymasterDevice>::value, + "AmlKeymasterDevice must be standard layout"); + static_assert(offsetof(AmlKeymasterDevice, device_) == 0, + "device_ must be the first member of AmlKeymasterDevice"); + static_assert(offsetof(AmlKeymasterDevice, device_.common) == 0, + "common must be the first member of keymaster2_device"); + + ALOGI("Creating device"); + ALOGD("Device address: %p", this); + + device_ = {}; + + device_.common.tag = HARDWARE_DEVICE_TAG; + device_.common.version = 1; + device_.common.module = const_cast<hw_module_t*>(module); + device_.common.close = close_device; + + device_.flags = KEYMASTER_SUPPORTS_EC; + + device_.configure = configure; + device_.add_rng_entropy = add_rng_entropy; + device_.generate_key = generate_key; + device_.get_key_characteristics = get_key_characteristics; + device_.import_key = import_key; + device_.export_key = export_key; + device_.attest_key = attest_key; + device_.upgrade_key = upgrade_key; + device_.delete_key = delete_key; + device_.delete_all_keys = nullptr; + device_.begin = begin; + device_.update = update; + device_.finish = finish; + device_.abort = abort; + + KM_context.fd = 0; + KM_session.ctx = NULL; + KM_session.session_id = 0; + + TEEC_Result rc = aml_keymaster_connect(&KM_context, &KM_session); + error_ = translate_error(rc); + if (rc != TEEC_SUCCESS) { + ALOGE("failed to connect to keymaster (0x%x)", rc); + return; + } + + GetVersionRequest version_request; + GetVersionResponse version_response; + error_ = Send(KM_GET_VERSION, version_request, &version_response); + if (error_ == KM_ERROR_INVALID_ARGUMENT || error_ == KM_ERROR_UNIMPLEMENTED) { + ALOGE("\"Bad parameters\" error on GetVersion call. Version 0 is not supported."); + error_ = KM_ERROR_VERSION_MISMATCH; + return; + } + message_version_ = MessageVersion(version_response.major_ver, version_response.minor_ver, + version_response.subminor_ver); + if (message_version_ < 0) { + // Can't translate version? Keymaster implementation must be newer. + ALOGE("Keymaster version %d.%d.%d not supported.", version_response.major_ver, + version_response.minor_ver, version_response.subminor_ver); + error_ = KM_ERROR_VERSION_MISMATCH; + } +} + +AmlKeymasterDevice::~AmlKeymasterDevice() { + aml_keymaster_disconnect(&KM_context, &KM_session); +} + +namespace { + +// Allocates a new buffer with malloc and copies the contents of |buffer| to it. Caller takes +// ownership of the returned buffer. +uint8_t* DuplicateBuffer(const uint8_t* buffer, size_t size) { + uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(size)); + if (tmp) { + memcpy(tmp, buffer, size); + } + return tmp; +} + +template <typename RequestType> +void AddClientAndAppData(const keymaster_blob_t* client_id, const keymaster_blob_t* app_data, + RequestType* request) { + request->additional_params.Clear(); + if (client_id) { + request->additional_params.push_back(TAG_APPLICATION_ID, *client_id); + } + if (app_data) { + request->additional_params.push_back(TAG_APPLICATION_DATA, *app_data); + } +} + +} // unnamed namespace + +struct tag_table_entry { + const char *name; + keymaster_tag_t tag; +}; + +static struct tag_table_entry tag_table[] = +{ + {"KM_TAG_PURPOSE", KM_TAG_PURPOSE}, + {"KM_TAG_ALGORITHM", KM_TAG_ALGORITHM}, + {"KM_TAG_KEY_SIZE", KM_TAG_KEY_SIZE}, + {"KM_TAG_BLOCK_MODE", KM_TAG_BLOCK_MODE}, + {"KM_TAG_DIGEST", KM_TAG_DIGEST}, + {"KM_TAG_PADDING", KM_TAG_PADDING}, + {"KM_TAG_CALLER_NONCE", KM_TAG_CALLER_NONCE}, + {"KM_TAG_MIN_MAC_LENGTH", KM_TAG_MIN_MAC_LENGTH}, + {"KM_TAG_RSA_PUBLIC_EXPONENT", KM_TAG_RSA_PUBLIC_EXPONENT}, + {"KM_TAG_BLOB_USAGE_REQUIREMENTS", KM_TAG_BLOB_USAGE_REQUIREMENTS}, + {"KM_TAG_BOOTLOADER_ONLY", KM_TAG_BOOTLOADER_ONLY}, + {"KM_TAG_ACTIVE_DATETIME", KM_TAG_ACTIVE_DATETIME}, + {"KM_TAG_ORIGINATION_EXPIRE_DATETIME", KM_TAG_ORIGINATION_EXPIRE_DATETIME}, + {"KM_TAG_USAGE_EXPIRE_DATETIME",KM_TAG_USAGE_EXPIRE_DATETIME}, + {"KM_TAG_MIN_SECONDS_BETWEEN_OPS",KM_TAG_MIN_SECONDS_BETWEEN_OPS}, + {"KM_TAG_MAX_USES_PER_BOOT",KM_TAG_MAX_USES_PER_BOOT}, + {"KM_TAG_ALL_USERS", KM_TAG_ALL_USERS}, + {"KM_TAG_USER_ID", KM_TAG_USER_ID}, + {"KM_TAG_USER_SECURE_ID",KM_TAG_USER_SECURE_ID}, + {"KM_TAG_NO_AUTH_REQUIRED",KM_TAG_NO_AUTH_REQUIRED}, + {"KM_TAG_USER_AUTH_TYPE ", KM_TAG_USER_AUTH_TYPE}, + {"KM_TAG_AUTH_TIMEOUT ",KM_TAG_AUTH_TIMEOUT }, + {"KM_TAG_ALL_APPLICATIONS ", KM_TAG_ALL_APPLICATIONS }, + {"KM_TAG_APPLICATION_ID", KM_TAG_APPLICATION_ID}, + {"KM_TAG_APPLICATION_DATA ",KM_TAG_APPLICATION_DATA }, + {"KM_TAG_CREATION_DATETIME ",KM_TAG_CREATION_DATETIME }, + {"KM_TAG_ORIGIN ", KM_TAG_ORIGIN }, + {"KM_TAG_ROLLBACK_RESISTANT ", KM_TAG_ROLLBACK_RESISTANT }, + {"KM_TAG_ROOT_OF_TRUST", KM_TAG_ROOT_OF_TRUST}, + {"KM_TAG_ASSOCIATED_DATA ",KM_TAG_ASSOCIATED_DATA}, + {"KM_TAG_NONCE", KM_TAG_NONCE}, + {"KM_TAG_AUTH_TOKEN",KM_TAG_AUTH_TOKEN}, + {"KM_TAG_MAC_LENGTH", KM_TAG_MAC_LENGTH}, +}; + +const size_t tag_table_size = sizeof(tag_table)/sizeof(struct tag_table_entry); + +void AmlKeymasterDevice::dump_tag_item_value(const char *name, const keymaster_key_param_t* item) +{ + keymaster_tag_type_t type = KM_INVALID; + + if (item) { + type = keymaster_tag_get_type(item->tag); + switch (type) { + case KM_ULONG: + case KM_ULONG_REP: + ALOGI("%s: %" PRIx64 "\n", name, item->long_integer); + //printf("%s: %" PRIx64 "\n", name, item->long_integer); + break; + case KM_DATE: + ALOGI("%s: %" PRIx64 "\n", name, item->date_time); + //printf("%s: %" PRIx64 "\n", name, item->date_time); + break; + case KM_BYTES: + case KM_BIGNUM: + ALOGI("%s: blob data: %p, len: 0x%zx\n", name, item->blob.data, item->blob.data_length); + //printf("%s: blob data: %p, len: 0x%zx\n", name, item->blob.data, item->blob.data_length); + break; + case KM_ENUM: + case KM_ENUM_REP: + ALOGI("%s: 0x%x\n", name, item->enumerated); + //printf("%s: 0x%x\n", name, item->enumerated); + break; + case KM_BOOL: + ALOGI("%s: 0x%x\n", name, item->boolean); + //printf("%s: 0x%x\n", name, item->boolean); + break; + case KM_UINT: + case KM_UINT_REP: + ALOGI("%s: 0x%x\n", name, item->integer); + //printf("%s: 0x%x\n", name, item->integer); + break; + default: + ALOGI("%s: invalid type: %d\n", name, type); + //printf("%s: invalid type: %d\n", name, type); + break; + } + } +} + +void AmlKeymasterDevice::dump_tags(const char *name, const keymaster_key_param_set_t *params) +{ + size_t i = 0, j =0; + keymaster_key_param_t* item = params->params; + + ALOGI("==== start dump %s, length (%zu)\n", name, params->length); + //printf("==== start dump %s, length (%zu)\n", name, params->length); + for (i = 0; i < params->length; i++) { + for (j = 0; j < tag_table_size; j++) { + if (tag_table[j].tag == item[i].tag) { + dump_tag_item_value(tag_table[j].name, &item[i]); + break; + } + } + } + ALOGI("==== end dump %s\n", name); + //printf("==== end dump %s\n", name); +} + +keymaster_error_t AmlKeymasterDevice::configure(const keymaster_key_param_set_t* params) { + ALOGD("Device received configure\n"); + + if (error_ != KM_ERROR_OK) { + return error_; + } + if (!params) { + return KM_ERROR_UNEXPECTED_NULL_POINTER; + } + + AuthorizationSet params_copy(*params); + ConfigureRequest request; + if (!params_copy.GetTagValue(TAG_OS_VERSION, &request.os_version) || + !params_copy.GetTagValue(TAG_OS_PATCHLEVEL, &request.os_patchlevel)) { + ALOGD("Configuration parameters must contain OS version and patch level"); + return KM_ERROR_INVALID_ARGUMENT; + } + + ConfigureResponse response; + keymaster_error_t err = Send(KM_CONFIGURE, request, &response); + if (err != KM_ERROR_OK) { + return err; + } + + return KM_ERROR_OK; +} + +keymaster_error_t AmlKeymasterDevice::add_rng_entropy(const uint8_t* data, size_t data_length) { + ALOGD("Device received add_rng_entropy"); + + if (error_ != KM_ERROR_OK) { + return error_; + } + + AddEntropyRequest request; + request.random_data.Reinitialize(data, data_length); + AddEntropyResponse response; + return Send(KM_ADD_RNG_ENTROPY, request, &response); +} + +keymaster_error_t AmlKeymasterDevice::simple_bin2ascii(uint8_t *data, size_t data_length, char *out) { + for (size_t i = 0; i < data_length; i++) { + if (((data[i] & 0xf0) >> 4) < 0xa) + out[i * 2] = ((data[i] & 0xf0) >> 4) + 48; + else + out[i * 2] = ((data[i] & 0xf0) >> 4) + 87; + if ((data[i] & 0xf) < 0xa) + out[i * 2 + 1] = (data[i] & 0xf) + 48; + else + out[i * 2 + 1] = (data[i] & 0xf) + 87; + } + + return KM_ERROR_OK; +} + +keymaster_error_t AmlKeymasterDevice::store_encrypted_key(keymaster_key_blob_t* key_blob) { + SHA256_CTX sha256_ctx; + UniquePtr<uint8_t[]> hash_buf(new (std::nothrow) uint8_t[SHA256_DIGEST_LENGTH + 1]); + UniquePtr<char[]> name_buf(new (std::nothrow) char [SHA256_DIGEST_LENGTH * 2 + 1]); + std::ofstream out; + char name[256]; + + // Hash key data to create filename. + Eraser sha256_ctx_eraser(sha256_ctx); + memset(name_buf.get(), 0, SHA256_DIGEST_LENGTH * 2 + 1); + SHA256_Init(&sha256_ctx); + SHA256_Update(&sha256_ctx, key_blob->key_material, key_blob->key_material_size); + SHA256_Final(hash_buf.get(), &sha256_ctx); + + simple_bin2ascii(hash_buf.get(), SHA256_DIGEST_LENGTH, name_buf.get()); + name_buf[SHA256_DIGEST_LENGTH * 2] = '\0'; + sprintf(name, "/data/tee/%s", name_buf.get()); + out.open(name, std::ofstream::out | std::ofstream::binary); + if (out.is_open()) { + out.write((const char *)key_blob->key_material, key_blob->key_material_size); + out.close(); + } else { + ALOGE("error opening key files\n"); + } + + return KM_ERROR_OK; +} + +keymaster_error_t AmlKeymasterDevice::delete_encrypted_key(const keymaster_key_blob_t* key_blob) { + SHA256_CTX sha256_ctx; + UniquePtr<uint8_t[]> hash_buf(new (std::nothrow) uint8_t[SHA256_DIGEST_LENGTH + 1]); + UniquePtr<char[]> name_buf(new (std::nothrow) char [SHA256_DIGEST_LENGTH * 2 + 1]); + std::ofstream out; + char name[256]; + int result = -1; + + // Hash key data to get filename. + Eraser sha256_ctx_eraser(sha256_ctx); + memset(name_buf.get(), 0, SHA256_DIGEST_LENGTH * 2 + 1); + SHA256_Init(&sha256_ctx); + SHA256_Update(&sha256_ctx, key_blob->key_material, key_blob->key_material_size); + SHA256_Final(hash_buf.get(), &sha256_ctx); + + simple_bin2ascii(hash_buf.get(), SHA256_DIGEST_LENGTH, name_buf.get()); + name_buf[SHA256_DIGEST_LENGTH * 2] = '\0'; + sprintf(name, "/data/tee/%s", name_buf.get()); + out.open(name, std::ofstream::out | std::ofstream::binary); + result = unlink(name); + + if (!result) { + return KM_ERROR_OK; + } else { + ALOGE("cannot locate %s\n", name); + return KM_ERROR_INVALID_OPERATION_HANDLE; + } +} + +keymaster_error_t AmlKeymasterDevice::generate_key( + const keymaster_key_param_set_t* params, keymaster_key_blob_t* key_blob, + keymaster_key_characteristics_t* characteristics) { + ALOGD("Device received generate_key"); + + if (error_ != KM_ERROR_OK) { + return error_; + } + if (!params) { + return KM_ERROR_UNEXPECTED_NULL_POINTER; + } + if (!key_blob) { + return KM_ERROR_OUTPUT_PARAMETER_NULL; + } + + GenerateKeyRequest request(message_version_); + request.key_description.Reinitialize(*params); + request.key_description.push_back(TAG_CREATION_DATETIME, java_time(time(NULL))); + + GenerateKeyResponse response(message_version_); + keymaster_error_t err = Send(KM_GENERATE_KEY, request, &response); + if (err != KM_ERROR_OK) { + return err; + } + + key_blob->key_material_size = response.key_blob.key_material_size; + key_blob->key_material = + DuplicateBuffer(response.key_blob.key_material, response.key_blob.key_material_size); + if (!key_blob->key_material) { + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + } + + if (characteristics) { + response.enforced.CopyToParamSet(&characteristics->hw_enforced); + response.unenforced.CopyToParamSet(&characteristics->sw_enforced); + } + + return KM_ERROR_OK; +} + +keymaster_error_t AmlKeymasterDevice::get_key_characteristics( + const keymaster_key_blob_t* key_blob, const keymaster_blob_t* client_id, + const keymaster_blob_t* app_data, keymaster_key_characteristics_t* characteristics) { + ALOGD("Device received get_key_characteristics"); + + if (error_ != KM_ERROR_OK) { + return error_; + } + if (!key_blob || !key_blob->key_material) { + return KM_ERROR_UNEXPECTED_NULL_POINTER; + } + if (!characteristics) { + return KM_ERROR_OUTPUT_PARAMETER_NULL; + } + + GetKeyCharacteristicsRequest request; + request.SetKeyMaterial(*key_blob); + AddClientAndAppData(client_id, app_data, &request); + + GetKeyCharacteristicsResponse response; + keymaster_error_t err = Send(KM_GET_KEY_CHARACTERISTICS, request, &response); + if (err != KM_ERROR_OK) { + return err; + } + + response.enforced.CopyToParamSet(&characteristics->hw_enforced); + response.unenforced.CopyToParamSet(&characteristics->sw_enforced); + + return KM_ERROR_OK; +} + +keymaster_error_t AmlKeymasterDevice::import_key( + const keymaster_key_param_set_t* params, keymaster_key_format_t key_format, + const keymaster_blob_t* key_data, keymaster_key_blob_t* key_blob, + keymaster_key_characteristics_t* characteristics) { + ALOGD("Device received import_key"); + + if (error_ != KM_ERROR_OK) { + return error_; + } + if (!params || !key_data) { + return KM_ERROR_UNEXPECTED_NULL_POINTER; + } + if (!key_blob) { + return KM_ERROR_OUTPUT_PARAMETER_NULL; + } + + ImportKeyRequest request(message_version_); + request.key_description.Reinitialize(*params); + request.key_description.push_back(TAG_CREATION_DATETIME, java_time(time(NULL))); + + dump_tags("import", &request.key_description); + request.key_format = key_format; + request.SetKeyMaterial(key_data->data, key_data->data_length); + + ImportKeyResponse response(message_version_); + keymaster_error_t err = Send(KM_IMPORT_KEY, request, &response); + if (err != KM_ERROR_OK) { + return err; + } + + key_blob->key_material_size = response.key_blob.key_material_size; + key_blob->key_material = + DuplicateBuffer(response.key_blob.key_material, response.key_blob.key_material_size); + if (!key_blob->key_material) { + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + } + + dump_tags("hw", &response.enforced); + dump_tags("sw", &response.unenforced); + if (characteristics) { + response.enforced.CopyToParamSet(&characteristics->hw_enforced); + response.unenforced.CopyToParamSet(&characteristics->sw_enforced); + } + + return KM_ERROR_OK; +} + +keymaster_error_t AmlKeymasterDevice::export_key(keymaster_key_format_t export_format, + const keymaster_key_blob_t* key_to_export, + const keymaster_blob_t* client_id, + const keymaster_blob_t* app_data, + keymaster_blob_t* export_data) { + ALOGD("Device received export_key"); + + if (error_ != KM_ERROR_OK) { + return error_; + } + if (!key_to_export || !key_to_export->key_material) { + return KM_ERROR_UNEXPECTED_NULL_POINTER; + } + if (!export_data) { + return KM_ERROR_OUTPUT_PARAMETER_NULL; + } + + export_data->data = nullptr; + export_data->data_length = 0; + + ExportKeyRequest request(message_version_); + request.key_format = export_format; + request.SetKeyMaterial(*key_to_export); + AddClientAndAppData(client_id, app_data, &request); + + ExportKeyResponse response(message_version_); + keymaster_error_t err = Send(KM_EXPORT_KEY, request, &response); + if (err != KM_ERROR_OK) { + return err; + } + + export_data->data_length = response.key_data_length; + export_data->data = DuplicateBuffer(response.key_data, response.key_data_length); + if (!export_data->data) { + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + } + + return KM_ERROR_OK; +} + +keymaster_error_t AmlKeymasterDevice::attest_key(const keymaster_key_blob_t* key_to_attest, + const keymaster_key_param_set_t* attest_params, + keymaster_cert_chain_t* cert_chain) { + ALOGD("Device received attest_key"); + + if (error_ != KM_ERROR_OK) { + return error_; + } + if (!key_to_attest || !attest_params) { + return KM_ERROR_UNEXPECTED_NULL_POINTER; + } + if (!cert_chain) { + return KM_ERROR_OUTPUT_PARAMETER_NULL; + } + + cert_chain->entry_count = 0; + cert_chain->entries = nullptr; + + AttestKeyRequest request; + request.SetKeyMaterial(*key_to_attest); + request.attest_params.Reinitialize(*attest_params); + + keymaster_blob_t attestation_challenge = {}; + request.attest_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge); + if (attestation_challenge.data_length > kMaximumAttestationChallengeLength) { + ALOGE("%zu-byte attestation challenge; only %zu bytes allowed", + attestation_challenge.data_length, kMaximumAttestationChallengeLength); + return KM_ERROR_INVALID_INPUT_LENGTH; + } + + AttestKeyResponse response; + keymaster_error_t err = Send(KM_ATTEST_KEY, request, &response); + if (err != KM_ERROR_OK) { + return err; + } + + // Allocate and clear storage for cert_chain. + keymaster_cert_chain_t& rsp_chain = response.certificate_chain; + cert_chain->entries = reinterpret_cast<keymaster_blob_t*>( + malloc(rsp_chain.entry_count * sizeof(*cert_chain->entries))); + if (!cert_chain->entries) { + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + } + cert_chain->entry_count = rsp_chain.entry_count; + for (keymaster_blob_t& entry : array_range(cert_chain->entries, cert_chain->entry_count)) { + entry = {}; + } + + // Copy cert_chain contents + size_t i = 0; + for (keymaster_blob_t& entry : array_range(rsp_chain.entries, rsp_chain.entry_count)) { + cert_chain->entries[i].data = DuplicateBuffer(entry.data, entry.data_length); + if (!cert_chain->entries[i].data) { + keymaster_free_cert_chain(cert_chain); + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + } + cert_chain->entries[i].data_length = entry.data_length; + ++i; + } + + return KM_ERROR_OK; +} + +keymaster_error_t AmlKeymasterDevice::upgrade_key(const keymaster_key_blob_t* key_to_upgrade, + const keymaster_key_param_set_t* upgrade_params, + keymaster_key_blob_t* upgraded_key) { + ALOGD("Device received upgrade_key"); + + if (error_ != KM_ERROR_OK) { + return error_; + } + if (!key_to_upgrade || !upgrade_params) { + return KM_ERROR_UNEXPECTED_NULL_POINTER; + } + if (!upgraded_key) { + return KM_ERROR_OUTPUT_PARAMETER_NULL; + } + + UpgradeKeyRequest request; + request.SetKeyMaterial(*key_to_upgrade); + request.upgrade_params.Reinitialize(*upgrade_params); + + UpgradeKeyResponse response; + keymaster_error_t err = Send(KM_UPGRADE_KEY, request, &response); + if (err != KM_ERROR_OK) { + return err; + } + + upgraded_key->key_material_size = response.upgraded_key.key_material_size; + upgraded_key->key_material = DuplicateBuffer(response.upgraded_key.key_material, + response.upgraded_key.key_material_size); + if (!upgraded_key->key_material) { + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + } + + return KM_ERROR_OK; +} + +keymaster_error_t AmlKeymasterDevice::delete_key(const keymaster_key_blob_t* key) { + (void)key; + return KM_ERROR_OK; +} + +keymaster_error_t AmlKeymasterDevice::begin(keymaster_purpose_t purpose, + const keymaster_key_blob_t* key, + const keymaster_key_param_set_t* in_params, + keymaster_key_param_set_t* out_params, + keymaster_operation_handle_t* operation_handle) { + ALOGD("Device received begin"); + + if (error_ != KM_ERROR_OK) { + return error_; + } + if (!key || !key->key_material) { + return KM_ERROR_UNEXPECTED_NULL_POINTER; + } + if (!operation_handle) { + return KM_ERROR_OUTPUT_PARAMETER_NULL; + } + + if (out_params) { + *out_params = {}; + } + + BeginOperationRequest request; + request.purpose = purpose; + request.SetKeyMaterial(*key); + request.additional_params.Reinitialize(*in_params); + + BeginOperationResponse response; + keymaster_error_t err = Send(KM_BEGIN_OPERATION, request, &response); + if (err != KM_ERROR_OK) { + return err; + } + + if (response.output_params.size() > 0) { + if (out_params) { + response.output_params.CopyToParamSet(out_params); + } else { + return KM_ERROR_OUTPUT_PARAMETER_NULL; + } + } + *operation_handle = response.op_handle; + + return KM_ERROR_OK; +} + +keymaster_error_t AmlKeymasterDevice::update(keymaster_operation_handle_t operation_handle, + const keymaster_key_param_set_t* in_params, + const keymaster_blob_t* input, + size_t* input_consumed, + keymaster_key_param_set_t* out_params, + keymaster_blob_t* output) { + ALOGD("Device received update"); + + if (error_ != KM_ERROR_OK) { + return error_; + } + if (!input) { + return KM_ERROR_UNEXPECTED_NULL_POINTER; + } + if (!input_consumed) { + return KM_ERROR_OUTPUT_PARAMETER_NULL; + } + + if (out_params) { + *out_params = {}; + } + if (output) { + *output = {}; + } + + UpdateOperationRequest request; + request.op_handle = operation_handle; + if (in_params) { + request.additional_params.Reinitialize(*in_params); + } + if (input && input->data_length > 0) { + size_t max_input_size = SEND_BUF_SIZE - request.SerializedSize(); + request.input.Reinitialize(input->data, std::min(input->data_length, max_input_size)); + } + + UpdateOperationResponse response; + keymaster_error_t err = Send(KM_UPDATE_OPERATION, request, &response); + if (err != KM_ERROR_OK) { + return err; + } + + if (response.output_params.size() > 0) { + if (out_params) { + response.output_params.CopyToParamSet(out_params); + } else { + return KM_ERROR_OUTPUT_PARAMETER_NULL; + } + } + *input_consumed = response.input_consumed; + if (output) { + output->data_length = response.output.available_read(); + output->data = DuplicateBuffer(response.output.peek_read(), output->data_length); + if (!output->data) { + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + } + } else if (response.output.available_read() > 0) { + return KM_ERROR_OUTPUT_PARAMETER_NULL; + } + + return KM_ERROR_OK; +} + +keymaster_error_t AmlKeymasterDevice::finish(keymaster_operation_handle_t operation_handle, + const keymaster_key_param_set_t* in_params, + const keymaster_blob_t* input, + const keymaster_blob_t* signature, + keymaster_key_param_set_t* out_params, + keymaster_blob_t* output) { + ALOGD("Device received finish"); + + if (error_ != KM_ERROR_OK) { + return error_; + } + if (input && input->data_length > kMaximumFinishInputLength) { + ALOGE("%zu-byte input to finish; only %zu bytes allowed", + input->data_length, kMaximumFinishInputLength); + return KM_ERROR_INVALID_INPUT_LENGTH; + } + + if (out_params) { + *out_params = {}; + } + if (output) { + *output = {}; + } + + FinishOperationRequest request; + request.op_handle = operation_handle; + if (signature && signature->data && signature->data_length > 0) { + request.signature.Reinitialize(signature->data, signature->data_length); + } + if (input && input->data && input->data_length) { + request.input.Reinitialize(input->data, input->data_length); + } + if (in_params) { + request.additional_params.Reinitialize(*in_params); + } + + FinishOperationResponse response; + keymaster_error_t err = Send(KM_FINISH_OPERATION, request, &response); + if (err != KM_ERROR_OK) { + return err; + } + + if (response.output_params.size() > 0) { + if (out_params) { + response.output_params.CopyToParamSet(out_params); + } else { + return KM_ERROR_OUTPUT_PARAMETER_NULL; + } + } + if (output) { + output->data_length = response.output.available_read(); + output->data = DuplicateBuffer(response.output.peek_read(), output->data_length); + if (!output->data) { + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + } + } else if (response.output.available_read() > 0) { + return KM_ERROR_OUTPUT_PARAMETER_NULL; + } + + return KM_ERROR_OK; +} + +keymaster_error_t AmlKeymasterDevice::abort(keymaster_operation_handle_t operation_handle) { + ALOGD("Device received abort"); + + if (error_ != KM_ERROR_OK) { + return error_; + } + + AbortOperationRequest request; + request.op_handle = operation_handle; + AbortOperationResponse response; + return Send(KM_ABORT_OPERATION, request, &response); +} + +hw_device_t* AmlKeymasterDevice::hw_device() { + return &device_.common; +} + +static inline AmlKeymasterDevice* convert_device(const keymaster2_device_t* dev) { + return reinterpret_cast<AmlKeymasterDevice*>(const_cast<keymaster2_device_t*>(dev)); +} + +/* static */ +int AmlKeymasterDevice::close_device(hw_device_t* dev) { + delete reinterpret_cast<AmlKeymasterDevice*>(dev); + return 0; +} + +/* static */ +keymaster_error_t AmlKeymasterDevice::configure(const keymaster2_device_t* dev, + const keymaster_key_param_set_t* params) { + return convert_device(dev)->configure(params); +} + +/* static */ +keymaster_error_t AmlKeymasterDevice::add_rng_entropy(const keymaster2_device_t* dev, + const uint8_t* data, size_t data_length) { + return convert_device(dev)->add_rng_entropy(data, data_length); +} + +/* static */ +keymaster_error_t AmlKeymasterDevice::generate_key( + const keymaster2_device_t* dev, const keymaster_key_param_set_t* params, + keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics) { + return convert_device(dev)->generate_key(params, key_blob, characteristics); +} + +/* static */ +keymaster_error_t AmlKeymasterDevice::get_key_characteristics( + const keymaster2_device_t* dev, const keymaster_key_blob_t* key_blob, + const keymaster_blob_t* client_id, const keymaster_blob_t* app_data, + keymaster_key_characteristics_t* characteristics) { + return convert_device(dev)->get_key_characteristics(key_blob, client_id, app_data, + characteristics); +} + +/* static */ +keymaster_error_t AmlKeymasterDevice::import_key( + const keymaster2_device_t* dev, const keymaster_key_param_set_t* params, + keymaster_key_format_t key_format, const keymaster_blob_t* key_data, + keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics) { + return convert_device(dev)->import_key(params, key_format, key_data, key_blob, characteristics); +} + +/* static */ +keymaster_error_t AmlKeymasterDevice::export_key(const keymaster2_device_t* dev, + keymaster_key_format_t export_format, + const keymaster_key_blob_t* key_to_export, + const keymaster_blob_t* client_id, + const keymaster_blob_t* app_data, + keymaster_blob_t* export_data) { + return convert_device(dev)->export_key(export_format, key_to_export, client_id, app_data, + export_data); +} + +/* static */ +keymaster_error_t AmlKeymasterDevice::attest_key(const keymaster2_device_t* dev, + const keymaster_key_blob_t* key_to_attest, + const keymaster_key_param_set_t* attest_params, + keymaster_cert_chain_t* cert_chain) { + return convert_device(dev)->attest_key(key_to_attest, attest_params, cert_chain); +} + +/* static */ +keymaster_error_t AmlKeymasterDevice::upgrade_key(const keymaster2_device_t* dev, + const keymaster_key_blob_t* key_to_upgrade, + const keymaster_key_param_set_t* upgrade_params, + keymaster_key_blob_t* upgraded_key) { + return convert_device(dev)->upgrade_key(key_to_upgrade, upgrade_params, upgraded_key); +} + +/* static */ +keymaster_error_t AmlKeymasterDevice::delete_key(const keymaster2_device_t* dev, + const keymaster_key_blob_t* key_blob) { + return convert_device(dev)->delete_key(key_blob); +} + +/* static */ +keymaster_error_t AmlKeymasterDevice::begin(const keymaster2_device_t* dev, + keymaster_purpose_t purpose, + const keymaster_key_blob_t* key, + const keymaster_key_param_set_t* in_params, + keymaster_key_param_set_t* out_params, + keymaster_operation_handle_t* operation_handle) { + return convert_device(dev)->begin(purpose, key, in_params, out_params, operation_handle); +} + +/* static */ +keymaster_error_t AmlKeymasterDevice::update( + const keymaster2_device_t* dev, keymaster_operation_handle_t operation_handle, + const keymaster_key_param_set_t* in_params, const keymaster_blob_t* input, + size_t* input_consumed, keymaster_key_param_set_t* out_params, keymaster_blob_t* output) { + return convert_device(dev)->update(operation_handle, in_params, input, input_consumed, + out_params, output); +} + +/* static */ +keymaster_error_t AmlKeymasterDevice::finish(const keymaster2_device_t* dev, + keymaster_operation_handle_t operation_handle, + const keymaster_key_param_set_t* in_params, + const keymaster_blob_t* input, + const keymaster_blob_t* signature, + keymaster_key_param_set_t* out_params, + keymaster_blob_t* output) { + return convert_device(dev)->finish(operation_handle, in_params, input, signature, out_params, + output); +} + +/* static */ +keymaster_error_t AmlKeymasterDevice::abort(const keymaster2_device_t* dev, + keymaster_operation_handle_t operation_handle) { + return convert_device(dev)->abort(operation_handle); +} + +keymaster_error_t AmlKeymasterDevice::Send(uint32_t command, const Serializable& req, + KeymasterResponse* rsp) { + uint32_t req_size = req.SerializedSize(); + + if (req_size > SEND_BUF_SIZE) { + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + } + //uint8_t send_buf[SEND_BUF_SIZE]; + UniquePtr<uint8_t[]> send_buf (new (std::nothrow) uint8_t[SEND_BUF_SIZE]); + if (!send_buf.get()) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + Eraser send_buf_eraser(send_buf.get(), SEND_BUF_SIZE); + req.Serialize(send_buf.get(), send_buf.get() + req_size); + + // Send it + //uint8_t recv_buf[RECV_BUF_SIZE]; + UniquePtr<uint8_t[]> recv_buf (new (std::nothrow) uint8_t[RECV_BUF_SIZE]); + if (!recv_buf.get()) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + Eraser recv_buf_eraser(recv_buf.get(), RECV_BUF_SIZE); + uint32_t rsp_size = RECV_BUF_SIZE; + ALOGD("Sending cmd: %u with %d byte request\n", command, (int)req.SerializedSize()); + TEEC_Result rc = aml_keymaster_call(&KM_session, command, send_buf.get(), req_size, recv_buf.get(), &rsp_size); + if (rc != TEEC_SUCCESS) { + return translate_error(rc); + } else { + ALOGD("Received %d byte response\n", rsp_size); + } + + const keymaster_message* msg = (keymaster_message*)recv_buf.get(); + const uint8_t* p = msg->payload; + if (!rsp->Deserialize(&p, p + rsp_size)) { + ALOGE("Error deserializing response of size %d\n", (int)rsp_size); + return KM_ERROR_UNKNOWN_ERROR; + } else if (rsp->error != KM_ERROR_OK) { + ALOGE("Response of size %d contained error code %d\n", (int)rsp_size, (int)rsp->error); + return rsp->error; + } + return rsp->error; +} + +} // namespace keymaster diff --git a/aml_keymaster_device.h b/aml_keymaster_device.h new file mode 100644 index 0000000..fb2a052 --- a/dev/null +++ b/aml_keymaster_device.h @@ -0,0 +1,167 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AML_KEYMASTER_AML_KEYMASTER_DEVICE_H_ +#define AML_KEYMASTER_AML_KEYMASTER_DEVICE_H_ + +#include <hardware/keymaster2.h> +#include <keymaster/android_keymaster_messages.h> + +extern "C" { +#include <tee_client_api.h> +} + +namespace keymaster { + +/** + * Aml Keymaster device. + * + * IMPORTANT MAINTAINER NOTE: Pointers to instances of this class must be castable to hw_device_t + * and keymaster_device. This means it must remain a standard layout class (no virtual functions and + * no data members which aren't standard layout), and device_ must be the first data member. + * Assertions in the constructor validate compliance with those constraints. + */ +class AmlKeymasterDevice { + public: + /* + * These are the only symbols that will be exported by libamlkeymaster. All functionality + * can be reached via the function pointers in device_. + */ + __attribute__((visibility("default"))) explicit AmlKeymasterDevice(const hw_module_t* module); + __attribute__((visibility("default"))) hw_device_t* hw_device(); + + ~AmlKeymasterDevice(); + + keymaster_error_t session_error() { return error_; } + + keymaster_error_t configure(const keymaster_key_param_set_t* params); + keymaster_error_t add_rng_entropy(const uint8_t* data, size_t data_length); + keymaster_error_t generate_key(const keymaster_key_param_set_t* params, + keymaster_key_blob_t* key_blob, + keymaster_key_characteristics_t* characteristics); + keymaster_error_t get_key_characteristics(const keymaster_key_blob_t* key_blob, + const keymaster_blob_t* client_id, + const keymaster_blob_t* app_data, + keymaster_key_characteristics_t* character); + keymaster_error_t import_key(const keymaster_key_param_set_t* params, + keymaster_key_format_t key_format, + const keymaster_blob_t* key_data, keymaster_key_blob_t* key_blob, + keymaster_key_characteristics_t* characteristics); + keymaster_error_t export_key(keymaster_key_format_t export_format, + const keymaster_key_blob_t* key_to_export, + const keymaster_blob_t* client_id, + const keymaster_blob_t* app_data, keymaster_blob_t* export_data); + keymaster_error_t attest_key(const keymaster_key_blob_t* key_to_attest, + const keymaster_key_param_set_t* attest_params, + keymaster_cert_chain_t* cert_chain); + keymaster_error_t upgrade_key(const keymaster_key_blob_t* key_to_upgrade, + const keymaster_key_param_set_t* upgrade_params, + keymaster_key_blob_t* upgraded_key); + keymaster_error_t delete_key(const keymaster_key_blob_t* key); + keymaster_error_t begin(keymaster_purpose_t purpose, const keymaster_key_blob_t* key, + const keymaster_key_param_set_t* in_params, + keymaster_key_param_set_t* out_params, + keymaster_operation_handle_t* operation_handle); + keymaster_error_t update(keymaster_operation_handle_t operation_handle, + const keymaster_key_param_set_t* in_params, + const keymaster_blob_t* input, size_t* input_consumed, + keymaster_key_param_set_t* out_params, keymaster_blob_t* output); + keymaster_error_t finish(keymaster_operation_handle_t operation_handle, + const keymaster_key_param_set_t* in_params, + const keymaster_blob_t* input, const keymaster_blob_t* signature, + keymaster_key_param_set_t* out_params, keymaster_blob_t* output); + keymaster_error_t abort(keymaster_operation_handle_t operation_handle); + + keymaster_error_t store_encrypted_key(keymaster_key_blob_t* key_blob); + keymaster_error_t delete_encrypted_key(const keymaster_key_blob_t* key_blob); + keymaster_error_t simple_bin2ascii(uint8_t *data, size_t data_length, char *out); + private: + keymaster_error_t Send(uint32_t command, const Serializable& request, + KeymasterResponse* response); + + /* + * These static methods are the functions referenced through the function pointers in + * keymaster_device. They're all trivial wrappers. + */ + static int close_device(hw_device_t* dev); + static keymaster_error_t configure(const keymaster2_device_t* dev, + const keymaster_key_param_set_t* params); + static keymaster_error_t add_rng_entropy(const keymaster2_device_t* dev, const uint8_t* data, + size_t data_length); + static keymaster_error_t generate_key(const keymaster2_device_t* dev, + const keymaster_key_param_set_t* params, + keymaster_key_blob_t* key_blob, + keymaster_key_characteristics_t* characteristics); + static keymaster_error_t get_key_characteristics(const keymaster2_device_t* dev, + const keymaster_key_blob_t* key_blob, + const keymaster_blob_t* client_id, + const keymaster_blob_t* app_data, + keymaster_key_characteristics_t* character); + static keymaster_error_t import_key(const keymaster2_device_t* dev, + const keymaster_key_param_set_t* params, + keymaster_key_format_t key_format, + const keymaster_blob_t* key_data, + keymaster_key_blob_t* key_blob, + keymaster_key_characteristics_t* characteristics); + static keymaster_error_t export_key(const keymaster2_device_t* dev, + keymaster_key_format_t export_format, + const keymaster_key_blob_t* key_to_export, + const keymaster_blob_t* client_id, + const keymaster_blob_t* app_data, + keymaster_blob_t* export_data); + static keymaster_error_t attest_key(const keymaster2_device_t* dev, + const keymaster_key_blob_t* key_to_attest, + const keymaster_key_param_set_t* attest_params, + keymaster_cert_chain_t* cert_chain); + static keymaster_error_t upgrade_key(const keymaster2_device_t* dev, + const keymaster_key_blob_t* key_to_upgrade, + const keymaster_key_param_set_t* upgrade_params, + keymaster_key_blob_t* upgraded_key); + static keymaster_error_t delete_key(const keymaster2_device_t* dev, + const keymaster_key_blob_t* key); + static keymaster_error_t delete_all_keys(const keymaster2_device_t* dev); + static keymaster_error_t begin(const keymaster2_device_t* dev, keymaster_purpose_t purpose, + const keymaster_key_blob_t* key, + const keymaster_key_param_set_t* in_params, + keymaster_key_param_set_t* out_params, + keymaster_operation_handle_t* operation_handle); + static keymaster_error_t update(const keymaster2_device_t* dev, + keymaster_operation_handle_t operation_handle, + const keymaster_key_param_set_t* in_params, + const keymaster_blob_t* input, size_t* input_consumed, + keymaster_key_param_set_t* out_params, keymaster_blob_t* output); + static keymaster_error_t finish(const keymaster2_device_t* dev, + keymaster_operation_handle_t operation_handle, + const keymaster_key_param_set_t* in_params, + const keymaster_blob_t* input, const keymaster_blob_t* signature, + keymaster_key_param_set_t* out_params, keymaster_blob_t* output); + static keymaster_error_t abort(const keymaster2_device_t* dev, + keymaster_operation_handle_t operation_handle); + + void dump_tags(const char *name, const keymaster_key_param_set_t *params); + void dump_tag_item_value(const char *name, const keymaster_key_param_t* item); + + keymaster2_device_t device_; + keymaster_error_t error_; + int32_t message_version_; + + TEEC_Context KM_context; + TEEC_Session KM_session; +}; + +} // namespace keymaster + +#endif // AML_KEYMASTER_AML_KEYMASTER_DEVICE_H_ diff --git a/aml_keymaster_ipc.cpp b/aml_keymaster_ipc.cpp new file mode 100644 index 0000000..9745a0d --- a/dev/null +++ b/aml_keymaster_ipc.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AmlKeymaster" + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <log/log.h> + +#include "keymaster_ipc.h" +#include "aml_keymaster_ipc.h" + +TEEC_Result aml_keymaster_connect(TEEC_Context *c, TEEC_Session *s) { + TEEC_Result result = TEEC_SUCCESS; + TEEC_UUID svc_id = TA_KEYMASTER_UUID; + TEEC_Operation operation; + uint32_t err_origin; + + memset(&operation, 0, sizeof(operation)); + + /* Initialize Context */ + result = TEEC_InitializeContext(NULL, c); + + if (result != TEEC_SUCCESS) { + ALOGD("TEEC_InitializeContext failed with error = %x\n", result); + return result; + } + /* Open Session */ + result = TEEC_OpenSession(c, s, &svc_id, + TEEC_LOGIN_PUBLIC, + NULL, NULL, + &err_origin); + + if (result != TEEC_SUCCESS) { + ALOGD("TEEC_Opensession failed with code 0x%x origin 0x%x",result, err_origin); + TEEC_FinalizeContext(c); + return result; + } + /* Init TA */ + operation.paramTypes = TEEC_PARAM_TYPES( + TEEC_NONE, TEEC_NONE, + TEEC_NONE, TEEC_NONE); + + result = TEEC_InvokeCommand(s, + KM_TA_INIT, + &operation, + NULL); + + ALOGE("create id: %d, ctx: %p, ctx: %p\n", s->session_id, s->ctx, c); + return result; +} + +TEEC_Result aml_keymaster_call(TEEC_Session *s, uint32_t cmd, void* in, uint32_t in_size, uint8_t* out, + uint32_t* out_size) { + TEEC_Result res = TEEC_SUCCESS; + TEEC_Operation op; + uint32_t ret_orig; + + memset(&op, 0, sizeof(op)); + + op.params[0].tmpref.buffer = in; + op.params[0].tmpref.size = in_size; + op.params[1].tmpref.buffer = out; + op.params[1].tmpref.size = *out_size; + op.paramTypes = TEEC_PARAM_TYPES( + TEEC_MEMREF_TEMP_INPUT, + TEEC_MEMREF_TEMP_OUTPUT, + TEEC_VALUE_OUTPUT, + TEEC_NONE); + + ALOGE("id: %d, ctx: %p, cmd: %d\n", s->session_id, s->ctx, cmd); + res = TEEC_InvokeCommand(s, cmd, &op, &ret_orig); + if (res != TEEC_SUCCESS) { + ALOGE("Invoke cmd: %u failed with res(%x), ret_orig(%x), return(%d)\n", + cmd, res, ret_orig, op.params[2].value.a); + } else { + *out_size = op.params[2].value.b; + } + + return res; +} + +TEEC_Result aml_keymaster_disconnect(TEEC_Context *c, TEEC_Session *s) { + TEEC_Operation operation; + TEEC_Result result = TEEC_SUCCESS; + + operation.paramTypes = TEEC_PARAM_TYPES( + TEEC_NONE, TEEC_NONE, + TEEC_NONE, TEEC_NONE); + + result = TEEC_InvokeCommand(s, + KM_TA_TERM, + &operation, + NULL); + + TEEC_CloseSession(s); + TEEC_FinalizeContext(c); + + return result; +} diff --git a/aml_keymaster_ipc.h b/aml_keymaster_ipc.h new file mode 100644 index 0000000..fa4a2da --- a/dev/null +++ b/aml_keymaster_ipc.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AML_KEYMASTER_AML_KEYMASTER_IPC_H_ +#define AML_KEYMASTER_AML_KEYMASTER_IPC_H_ + +extern "C" { +#include <tee_client_api.h> +} + +__BEGIN_DECLS + +TEEC_Result aml_keymaster_connect(TEEC_Context *c, TEEC_Session *s); +TEEC_Result aml_keymaster_call(TEEC_Session *s, uint32_t cmd, void* in, uint32_t in_size, uint8_t* out, + uint32_t* out_size); +TEEC_Result aml_keymaster_disconnect(TEEC_Context *c, TEEC_Session *s); + +__END_DECLS + +#endif // AML_KEYMASTER_AML_KEYMASTER_IPC_H_ diff --git a/keymaster_ipc.h b/keymaster_ipc.h new file mode 100644 index 0000000..1bbf2c7 --- a/dev/null +++ b/keymaster_ipc.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// clang-format off + +#define KEYMASTER_PORT "com.android.trusty.keymaster" +#define KEYMASTER_MAX_BUFFER_LENGTH 4096 + +/* This UUID is generated with uuidgen + the ITU-T UUID generator at http://www.itu.int/ITU-T/asn1/uuid.html */ +#define TA_KEYMASTER_UUID {0x8efb1e1c, 0x37e5, 0x4326, \ + { 0xa5, 0xd6, 0x8c, 0x33, 0x72, 0x6c, 0x7d, 0x57} } + +// Commands +enum keymaster_command : uint32_t { + KEYMASTER_RESP_BIT = 1, + KEYMASTER_STOP_BIT = 2, + KEYMASTER_REQ_SHIFT = 2, + + KM_GENERATE_KEY = (0 << KEYMASTER_REQ_SHIFT), + KM_BEGIN_OPERATION = (1 << KEYMASTER_REQ_SHIFT), + KM_UPDATE_OPERATION = (2 << KEYMASTER_REQ_SHIFT), + KM_FINISH_OPERATION = (3 << KEYMASTER_REQ_SHIFT), + KM_ABORT_OPERATION = (4 << KEYMASTER_REQ_SHIFT), + KM_IMPORT_KEY = (5 << KEYMASTER_REQ_SHIFT), + KM_EXPORT_KEY = (6 << KEYMASTER_REQ_SHIFT), + KM_GET_VERSION = (7 << KEYMASTER_REQ_SHIFT), + KM_ADD_RNG_ENTROPY = (8 << KEYMASTER_REQ_SHIFT), + KM_GET_SUPPORTED_ALGORITHMS = (9 << KEYMASTER_REQ_SHIFT), + KM_GET_SUPPORTED_BLOCK_MODES = (10 << KEYMASTER_REQ_SHIFT), + KM_GET_SUPPORTED_PADDING_MODES = (11 << KEYMASTER_REQ_SHIFT), + KM_GET_SUPPORTED_DIGESTS = (12 << KEYMASTER_REQ_SHIFT), + KM_GET_SUPPORTED_IMPORT_FORMATS = (13 << KEYMASTER_REQ_SHIFT), + KM_GET_SUPPORTED_EXPORT_FORMATS = (14 << KEYMASTER_REQ_SHIFT), + KM_GET_KEY_CHARACTERISTICS = (15 << KEYMASTER_REQ_SHIFT), + KM_ATTEST_KEY = (16 << KEYMASTER_REQ_SHIFT), + KM_UPGRADE_KEY = (17 << KEYMASTER_REQ_SHIFT), + KM_CONFIGURE = (18 << KEYMASTER_REQ_SHIFT), + + KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT), + KM_SET_ATTESTATION_KEY = (0x2000 << KEYMASTER_REQ_SHIFT), + KM_APPEND_ATTESTATION_CERT_CHAIN = (0x3000 << KEYMASTER_REQ_SHIFT), + + KM_TA_INIT = (0x10000 << KEYMASTER_REQ_SHIFT), + KM_TA_TERM = (0x10001 << KEYMASTER_REQ_SHIFT), +}; + +#ifdef __ANDROID__ + +/** + * keymaster_message - Serial header for communicating with KM server + * @cmd: the command, one of keymaster_command. + * @payload: start of the serialized command specific payload + */ +struct keymaster_message { + uint32_t cmd; + uint8_t payload[0]; +}; + +#endif diff --git a/module.cpp b/module.cpp new file mode 100644 index 0000000..b9ee918 --- a/dev/null +++ b/module.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <errno.h> +#include <string.h> + +#include <hardware/hardware.h> +#include <hardware/keymaster0.h> + +#include "aml_keymaster_device.h" + +using keymaster::AmlKeymasterDevice; + +/* + * Generic device handling + */ +static int aml_keymaster_open(const hw_module_t* module, const char* name, hw_device_t** device) { + if (strcmp(name, KEYSTORE_KEYMASTER) != 0) { + return -EINVAL; + } + + AmlKeymasterDevice* dev = new AmlKeymasterDevice(module); + if (dev == NULL) { + return -ENOMEM; + } + *device = dev->hw_device(); + // Do not delete dev; it will get cleaned up when the caller calls device->close(), and must + // exist until then. + return 0; +} + +static struct hw_module_methods_t keystore_module_methods = { + .open = aml_keymaster_open, +}; + +struct keystore_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = { + .common = + { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = KEYMASTER_MODULE_API_VERSION_2_0, + .hal_api_version = HARDWARE_HAL_API_VERSION, + .id = KEYSTORE_HARDWARE_MODULE_ID, + .name = "Amlogic Keymaster HAL", + .author = "Amlogic Inc.", + .methods = &keystore_module_methods, + .dso = 0, + .reserved = {}, + }, +}; diff --git a/unit_test/android_keymaster_messages_test.cpp b/unit_test/android_keymaster_messages_test.cpp new file mode 100644 index 0000000..f7e65bc --- a/dev/null +++ b/unit_test/android_keymaster_messages_test.cpp @@ -0,0 +1,732 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <UniquePtr.h> + +#include <gtest/gtest.h> + +#include <keymaster/android_keymaster.h> +#include <keymaster/android_keymaster_utils.h> +#include <keymaster/keymaster_tags.h> + +#include "android_keymaster_test_utils.h" + +namespace keymaster { +namespace test { + +/** + * Serialize and deserialize a message. + */ +template <typename Message> +Message* round_trip(int32_t ver, const Message& message, size_t expected_size) { + size_t size = message.SerializedSize(); + EXPECT_EQ(expected_size, size); + if (size == 0) + return NULL; + + UniquePtr<uint8_t[]> buf(new uint8_t[size]); + EXPECT_EQ(buf.get() + size, message.Serialize(buf.get(), buf.get() + size)); + + Message* deserialized = new Message(ver); + const uint8_t* p = buf.get(); + EXPECT_TRUE(deserialized->Deserialize(&p, p + size)); + EXPECT_EQ((ptrdiff_t)size, p - buf.get()); + return deserialized; +} + +struct EmptyKeymasterResponse : public KeymasterResponse { + explicit EmptyKeymasterResponse(int32_t ver) : KeymasterResponse(ver) {} + size_t NonErrorSerializedSize() const { return 1; } + uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* /* end */) const { + *buf++ = 0; + return buf; + } + bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) { + if (*buf_ptr >= end) + return false; + EXPECT_EQ(0, **buf_ptr); + (*buf_ptr)++; + return true; + } +}; + +TEST(RoundTrip, EmptyKeymasterResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + EmptyKeymasterResponse msg(ver); + msg.error = KM_ERROR_OK; + + UniquePtr<EmptyKeymasterResponse> deserialized(round_trip(ver, msg, 5)); + } +} + +TEST(RoundTrip, EmptyKeymasterResponseError) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + EmptyKeymasterResponse msg(ver); + msg.error = KM_ERROR_MEMORY_ALLOCATION_FAILED; + + UniquePtr<EmptyKeymasterResponse> deserialized(round_trip(ver, msg, 4)); + } +} + +TEST(RoundTrip, SupportedByAlgorithmRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + SupportedByAlgorithmRequest req(ver); + req.algorithm = KM_ALGORITHM_EC; + + UniquePtr<SupportedByAlgorithmRequest> deserialized(round_trip(ver, req, 4)); + EXPECT_EQ(KM_ALGORITHM_EC, deserialized->algorithm); + } +} + +TEST(RoundTrip, SupportedByAlgorithmAndPurposeRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + SupportedByAlgorithmAndPurposeRequest req(ver); + req.algorithm = KM_ALGORITHM_EC; + req.purpose = KM_PURPOSE_DECRYPT; + + UniquePtr<SupportedByAlgorithmAndPurposeRequest> deserialized(round_trip(ver, req, 8)); + EXPECT_EQ(KM_ALGORITHM_EC, deserialized->algorithm); + EXPECT_EQ(KM_PURPOSE_DECRYPT, deserialized->purpose); + } +} + +TEST(RoundTrip, SupportedResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + SupportedResponse<keymaster_digest_t> rsp(ver); + keymaster_digest_t digests[] = {KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1}; + rsp.error = KM_ERROR_OK; + rsp.SetResults(digests); + + UniquePtr<SupportedResponse<keymaster_digest_t>> deserialized(round_trip(ver, rsp, 20)); + EXPECT_EQ(array_length(digests), deserialized->results_length); + EXPECT_EQ(0, memcmp(deserialized->results, digests, array_size(digests))); + } +} + +static keymaster_key_param_t params[] = { + Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), + Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), + Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), + Authorization(TAG_USER_ID, 7), + Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD), + Authorization(TAG_APPLICATION_ID, "app_id", 6), + Authorization(TAG_AUTH_TIMEOUT, 300), +}; +uint8_t TEST_DATA[] = "a key blob"; + +TEST(RoundTrip, GenerateKeyRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + GenerateKeyRequest req(ver); + req.key_description.Reinitialize(params, array_length(params)); + UniquePtr<GenerateKeyRequest> deserialized(round_trip(ver, req, 78)); + EXPECT_EQ(deserialized->key_description, req.key_description); + } +} + +TEST(RoundTrip, GenerateKeyResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + GenerateKeyResponse rsp(ver); + rsp.error = KM_ERROR_OK; + rsp.key_blob.key_material = dup_array(TEST_DATA); + rsp.key_blob.key_material_size = array_length(TEST_DATA); + rsp.enforced.Reinitialize(params, array_length(params)); + + UniquePtr<GenerateKeyResponse> deserialized(round_trip(ver, rsp, 109)); + EXPECT_EQ(KM_ERROR_OK, deserialized->error); + EXPECT_EQ(deserialized->enforced, rsp.enforced); + EXPECT_EQ(deserialized->unenforced, rsp.unenforced); + } +} + +TEST(RoundTrip, GenerateKeyResponseTestError) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + GenerateKeyResponse rsp(ver); + rsp.error = KM_ERROR_UNSUPPORTED_ALGORITHM; + rsp.key_blob.key_material = dup_array(TEST_DATA); + rsp.key_blob.key_material_size = array_length(TEST_DATA); + rsp.enforced.Reinitialize(params, array_length(params)); + + UniquePtr<GenerateKeyResponse> deserialized(round_trip(ver, rsp, 4)); + EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM, deserialized->error); + EXPECT_EQ(0U, deserialized->enforced.size()); + EXPECT_EQ(0U, deserialized->unenforced.size()); + EXPECT_EQ(0U, deserialized->key_blob.key_material_size); + } +} + +TEST(RoundTrip, GetKeyCharacteristicsRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + GetKeyCharacteristicsRequest req(ver); + req.additional_params.Reinitialize(params, array_length(params)); + req.SetKeyMaterial("foo", 3); + + UniquePtr<GetKeyCharacteristicsRequest> deserialized(round_trip(ver, req, 85)); + EXPECT_EQ(7U, deserialized->additional_params.size()); + EXPECT_EQ(3U, deserialized->key_blob.key_material_size); + EXPECT_EQ(0, memcmp(deserialized->key_blob.key_material, "foo", 3)); + } +} + +TEST(RoundTrip, GetKeyCharacteristicsResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + GetKeyCharacteristicsResponse msg(ver); + msg.error = KM_ERROR_OK; + msg.enforced.Reinitialize(params, array_length(params)); + msg.unenforced.Reinitialize(params, array_length(params)); + + UniquePtr<GetKeyCharacteristicsResponse> deserialized(round_trip(ver, msg, 160)); + EXPECT_EQ(msg.enforced, deserialized->enforced); + EXPECT_EQ(msg.unenforced, deserialized->unenforced); + } +} + +TEST(RoundTrip, BeginOperationRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + BeginOperationRequest msg(ver); + msg.purpose = KM_PURPOSE_SIGN; + msg.SetKeyMaterial("foo", 3); + msg.additional_params.Reinitialize(params, array_length(params)); + + UniquePtr<BeginOperationRequest> deserialized(round_trip(ver, msg, 89)); + EXPECT_EQ(KM_PURPOSE_SIGN, deserialized->purpose); + EXPECT_EQ(3U, deserialized->key_blob.key_material_size); + EXPECT_EQ(0, memcmp(deserialized->key_blob.key_material, "foo", 3)); + EXPECT_EQ(msg.additional_params, deserialized->additional_params); + } +} + +TEST(RoundTrip, BeginOperationResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + BeginOperationResponse msg(ver); + msg.error = KM_ERROR_OK; + msg.op_handle = 0xDEADBEEF; + msg.output_params.push_back(Authorization(TAG_NONCE, "foo", 3)); + + UniquePtr<BeginOperationResponse> deserialized; + switch (ver) { + case 0: + deserialized.reset(round_trip(ver, msg, 12)); + break; + case 1: + case 2: + case 3: + deserialized.reset(round_trip(ver, msg, 39)); + break; + default: + FAIL(); + } + + EXPECT_EQ(KM_ERROR_OK, deserialized->error); + EXPECT_EQ(0xDEADBEEF, deserialized->op_handle); + + switch (ver) { + case 0: + EXPECT_EQ(0U, deserialized->output_params.size()); + break; + case 1: + case 2: + case 3: + EXPECT_EQ(msg.output_params, deserialized->output_params); + break; + default: + FAIL(); + } + } +} + +TEST(RoundTrip, BeginOperationResponseError) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + BeginOperationResponse msg(ver); + msg.error = KM_ERROR_INVALID_OPERATION_HANDLE; + msg.op_handle = 0xDEADBEEF; + + UniquePtr<BeginOperationResponse> deserialized(round_trip(ver, msg, 4)); + EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, deserialized->error); + } +} + +TEST(RoundTrip, UpdateOperationRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + UpdateOperationRequest msg(ver); + msg.op_handle = 0xDEADBEEF; + msg.input.Reinitialize("foo", 3); + + UniquePtr<UpdateOperationRequest> deserialized; + switch (ver) { + case 0: + deserialized.reset(round_trip(ver, msg, 15)); + break; + case 1: + case 2: + case 3: + deserialized.reset(round_trip(ver, msg, 27)); + break; + default: + FAIL(); + } + EXPECT_EQ(3U, deserialized->input.available_read()); + EXPECT_EQ(0, memcmp(deserialized->input.peek_read(), "foo", 3)); + } +} + +TEST(RoundTrip, UpdateOperationResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + UpdateOperationResponse msg(ver); + msg.error = KM_ERROR_OK; + msg.output.Reinitialize("foo", 3); + msg.input_consumed = 99; + msg.output_params.push_back(TAG_APPLICATION_ID, "bar", 3); + + UniquePtr<UpdateOperationResponse> deserialized; + switch (ver) { + case 0: + deserialized.reset(round_trip(ver, msg, 11)); + break; + case 1: + deserialized.reset(round_trip(ver, msg, 15)); + break; + case 2: + case 3: + deserialized.reset(round_trip(ver, msg, 42)); + break; + default: + FAIL(); + } + EXPECT_EQ(KM_ERROR_OK, deserialized->error); + EXPECT_EQ(3U, deserialized->output.available_read()); + EXPECT_EQ(0, memcmp(deserialized->output.peek_read(), "foo", 3)); + + switch (ver) { + case 0: + EXPECT_EQ(0U, deserialized->input_consumed); + break; + case 1: + EXPECT_EQ(99U, deserialized->input_consumed); + break; + case 2: + case 3: + EXPECT_EQ(99U, deserialized->input_consumed); + EXPECT_EQ(1U, deserialized->output_params.size()); + break; + default: + FAIL(); + } + } +} + +TEST(RoundTrip, FinishOperationRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + FinishOperationRequest msg(ver); + msg.op_handle = 0xDEADBEEF; + msg.signature.Reinitialize("bar", 3); + msg.input.Reinitialize("baz", 3); + + UniquePtr<FinishOperationRequest> deserialized; + switch (ver) { + case 0: + deserialized.reset(round_trip(ver, msg, 15)); + break; + case 1: + case 2: + deserialized.reset(round_trip(ver, msg, 27)); + break; + case 3: + deserialized.reset(round_trip(ver, msg, 34)); + break; + default: + FAIL(); + } + EXPECT_EQ(0xDEADBEEF, deserialized->op_handle); + EXPECT_EQ(3U, deserialized->signature.available_read()); + EXPECT_EQ(0, memcmp(deserialized->signature.peek_read(), "bar", 3)); + } +} + +TEST(Round_Trip, FinishOperationResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + FinishOperationResponse msg(ver); + msg.error = KM_ERROR_OK; + msg.output.Reinitialize("foo", 3); + + UniquePtr<FinishOperationResponse> deserialized; + switch (ver) { + case 0: + case 1: + deserialized.reset(round_trip(ver, msg, 11)); + break; + case 2: + case 3: + deserialized.reset(round_trip(ver, msg, 23)); + break; + default: + FAIL(); + } + EXPECT_EQ(msg.error, deserialized->error); + EXPECT_EQ(msg.output.available_read(), deserialized->output.available_read()); + EXPECT_EQ(0, memcmp(msg.output.peek_read(), deserialized->output.peek_read(), + msg.output.available_read())); + } +} + +TEST(RoundTrip, ImportKeyRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + ImportKeyRequest msg(ver); + msg.key_description.Reinitialize(params, array_length(params)); + msg.key_format = KM_KEY_FORMAT_X509; + msg.SetKeyMaterial("foo", 3); + + UniquePtr<ImportKeyRequest> deserialized(round_trip(ver, msg, 89)); + EXPECT_EQ(msg.key_description, deserialized->key_description); + EXPECT_EQ(msg.key_format, deserialized->key_format); + EXPECT_EQ(msg.key_data_length, deserialized->key_data_length); + EXPECT_EQ(0, memcmp(msg.key_data, deserialized->key_data, msg.key_data_length)); + } +} + +TEST(RoundTrip, ImportKeyResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + ImportKeyResponse msg(ver); + msg.error = KM_ERROR_OK; + msg.SetKeyMaterial("foo", 3); + msg.enforced.Reinitialize(params, array_length(params)); + msg.unenforced.Reinitialize(params, array_length(params)); + + UniquePtr<ImportKeyResponse> deserialized(round_trip(ver, msg, 167)); + EXPECT_EQ(msg.error, deserialized->error); + EXPECT_EQ(msg.key_blob.key_material_size, deserialized->key_blob.key_material_size); + EXPECT_EQ(0, memcmp(msg.key_blob.key_material, deserialized->key_blob.key_material, + msg.key_blob.key_material_size)); + EXPECT_EQ(msg.enforced, deserialized->enforced); + EXPECT_EQ(msg.unenforced, deserialized->unenforced); + } +} + +TEST(RoundTrip, ExportKeyRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + ExportKeyRequest msg(ver); + msg.additional_params.Reinitialize(params, array_length(params)); + msg.key_format = KM_KEY_FORMAT_X509; + msg.SetKeyMaterial("foo", 3); + + UniquePtr<ExportKeyRequest> deserialized(round_trip(ver, msg, 89)); + EXPECT_EQ(msg.additional_params, deserialized->additional_params); + EXPECT_EQ(msg.key_format, deserialized->key_format); + EXPECT_EQ(3U, deserialized->key_blob.key_material_size); + EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3)); + } +} + +TEST(RoundTrip, ExportKeyResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + ExportKeyResponse msg(ver); + msg.error = KM_ERROR_OK; + msg.SetKeyMaterial("foo", 3); + + UniquePtr<ExportKeyResponse> deserialized(round_trip(ver, msg, 11)); + EXPECT_EQ(3U, deserialized->key_data_length); + EXPECT_EQ(0, memcmp("foo", deserialized->key_data, 3)); + } +} + +TEST(RoundTrip, DeleteKeyRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + DeleteKeyRequest msg(ver); + msg.SetKeyMaterial("foo", 3); + + UniquePtr<DeleteKeyRequest> deserialized(round_trip(ver, msg, 7)); + EXPECT_EQ(3U, deserialized->key_blob.key_material_size); + EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3)); + } +} + +TEST(RoundTrip, DeleteKeyResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + DeleteKeyResponse msg(ver); + UniquePtr<DeleteKeyResponse> deserialized(round_trip(ver, msg, 4)); + } +} + +TEST(RoundTrip, DeleteAllKeysRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + DeleteAllKeysRequest msg(ver); + UniquePtr<DeleteAllKeysRequest> deserialized(round_trip(ver, msg, 0)); + } +} + +TEST(RoundTrip, DeleteAllKeysResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + DeleteAllKeysResponse msg(ver); + UniquePtr<DeleteAllKeysResponse> deserialized(round_trip(ver, msg, 4)); + } +} + +TEST(RoundTrip, GetVersionRequest) { + GetVersionRequest msg; + + size_t size = msg.SerializedSize(); + ASSERT_EQ(0U, size); + + UniquePtr<uint8_t[]> buf(new uint8_t[size]); + EXPECT_EQ(buf.get() + size, msg.Serialize(buf.get(), buf.get() + size)); + + GetVersionRequest deserialized; + const uint8_t* p = buf.get(); + EXPECT_TRUE(deserialized.Deserialize(&p, p + size)); + EXPECT_EQ((ptrdiff_t)size, p - buf.get()); +} + +TEST(RoundTrip, GetVersionResponse) { + GetVersionResponse msg; + msg.error = KM_ERROR_OK; + msg.major_ver = 9; + msg.minor_ver = 98; + msg.subminor_ver = 38; + + size_t size = msg.SerializedSize(); + ASSERT_EQ(7U, size); + + UniquePtr<uint8_t[]> buf(new uint8_t[size]); + EXPECT_EQ(buf.get() + size, msg.Serialize(buf.get(), buf.get() + size)); + + GetVersionResponse deserialized; + const uint8_t* p = buf.get(); + EXPECT_TRUE(deserialized.Deserialize(&p, p + size)); + EXPECT_EQ((ptrdiff_t)size, p - buf.get()); + EXPECT_EQ(9U, msg.major_ver); + EXPECT_EQ(98U, msg.minor_ver); + EXPECT_EQ(38U, msg.subminor_ver); +} + +TEST(RoundTrip, ConfigureRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + ConfigureRequest req(ver); + req.os_version = 1; + req.os_patchlevel = 1; + + UniquePtr<ConfigureRequest> deserialized(round_trip(ver, req, 8)); + EXPECT_EQ(deserialized->os_version, req.os_version); + EXPECT_EQ(deserialized->os_patchlevel, req.os_patchlevel); + } +} + +TEST(RoundTrip, ConfigureResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + ConfigureResponse rsp(ver); + UniquePtr<ConfigureResponse> deserialized(round_trip(ver, rsp, 4)); + } +} + +TEST(RoundTrip, AddEntropyRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + AddEntropyRequest msg(ver); + msg.random_data.Reinitialize("foo", 3); + + UniquePtr<AddEntropyRequest> deserialized(round_trip(ver, msg, 7)); + EXPECT_EQ(3U, deserialized->random_data.available_read()); + EXPECT_EQ(0, memcmp("foo", deserialized->random_data.peek_read(), 3)); + } +} + +TEST(RoundTrip, AddEntropyResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + AddEntropyResponse msg(ver); + UniquePtr<AddEntropyResponse> deserialized(round_trip(ver, msg, 4)); + } +} + +TEST(RoundTrip, AbortOperationRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + AbortOperationRequest msg(ver); + UniquePtr<AbortOperationRequest> deserialized(round_trip(ver, msg, 8)); + } +} + +TEST(RoundTrip, AbortOperationResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + AbortOperationResponse msg(ver); + UniquePtr<AbortOperationResponse> deserialized(round_trip(ver, msg, 4)); + } +} + +TEST(RoundTrip, AttestKeyRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + AttestKeyRequest msg(ver); + msg.SetKeyMaterial("foo", 3); + msg.attest_params.Reinitialize(params, array_length(params)); + + UniquePtr<AttestKeyRequest> deserialized(round_trip(ver, msg, 85)); + EXPECT_EQ(3U, deserialized->key_blob.key_material_size); + EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3)); + EXPECT_EQ(msg.attest_params, deserialized->attest_params); + } +} + +TEST(RoundTrip, AttestKeyResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + AttestKeyResponse msg(ver); + msg.error = KM_ERROR_OK; + EXPECT_TRUE(msg.AllocateChain(3)); + msg.certificate_chain.entries[0] = {dup_buffer("foo", 3), 3}; + msg.certificate_chain.entries[1] = {dup_buffer("bar", 3), 3}; + msg.certificate_chain.entries[2] = {dup_buffer("baz", 3), 3}; + + UniquePtr<AttestKeyResponse> deserialized(round_trip(ver, msg, 29)); + keymaster_cert_chain_t* chain = &deserialized->certificate_chain; + + EXPECT_NE(nullptr, chain->entries); + EXPECT_EQ(3U, chain->entry_count); + EXPECT_EQ(3U, chain->entries[0].data_length); + EXPECT_EQ(0, memcmp("foo", chain->entries[0].data, 3)); + EXPECT_EQ(3U, chain->entries[1].data_length); + EXPECT_EQ(0, memcmp("bar", chain->entries[1].data, 3)); + EXPECT_EQ(3U, chain->entries[2].data_length); + EXPECT_EQ(0, memcmp("baz", chain->entries[2].data, 3)); + } +} + +TEST(RoundTrip, UpgradeKeyRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + UpgradeKeyRequest msg(ver); + msg.SetKeyMaterial("foo", 3); + msg.upgrade_params.Reinitialize(params, array_length(params)); + + UniquePtr<UpgradeKeyRequest> deserialized(round_trip(ver, msg, 85)); + EXPECT_EQ(3U, deserialized->key_blob.key_material_size); + EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3)); + EXPECT_EQ(msg.upgrade_params, deserialized->upgrade_params); + } +} + +TEST(RoundTrip, UpgradeKeyResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + UpgradeKeyResponse req(ver); + req.error = KM_ERROR_OK; + req.upgraded_key.key_material = dup_array(TEST_DATA); + req.upgraded_key.key_material_size = array_length(TEST_DATA); + + UniquePtr<UpgradeKeyResponse> deserialized(round_trip(ver, req, 19)); + EXPECT_EQ(KM_ERROR_OK, deserialized->error); + EXPECT_EQ(req.upgraded_key.key_material_size, deserialized->upgraded_key.key_material_size); + EXPECT_EQ(0, memcmp(req.upgraded_key.key_material, deserialized->upgraded_key.key_material, + req.upgraded_key.key_material_size)); + } +} + +uint8_t msgbuf[] = { + 220, 88, 183, 255, 71, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 173, 0, 0, 0, 228, 174, 98, 187, 191, 135, 253, 200, 51, 230, 114, 247, 151, 109, + 237, 79, 87, 32, 94, 5, 204, 46, 154, 30, 91, 6, 103, 148, 254, 129, 65, 171, 228, + 167, 224, 163, 9, 15, 206, 90, 58, 11, 205, 55, 211, 33, 87, 178, 149, 91, 28, 236, + 218, 112, 231, 34, 82, 82, 134, 103, 137, 115, 27, 156, 102, 159, 220, 226, 89, 42, 25, + 37, 9, 84, 239, 76, 161, 198, 72, 167, 163, 39, 91, 148, 191, 17, 191, 87, 169, 179, + 136, 10, 194, 154, 4, 40, 107, 109, 61, 161, 20, 176, 247, 13, 214, 106, 229, 45, 17, + 5, 60, 189, 64, 39, 166, 208, 14, 57, 25, 140, 148, 25, 177, 246, 189, 43, 181, 88, + 204, 29, 126, 224, 100, 143, 93, 60, 57, 249, 55, 0, 87, 83, 227, 224, 166, 59, 214, + 81, 144, 129, 58, 6, 57, 46, 254, 232, 41, 220, 209, 230, 167, 138, 158, 94, 180, 125, + 247, 26, 162, 116, 238, 202, 187, 100, 65, 13, 180, 44, 245, 159, 83, 161, 176, 58, 72, + 236, 109, 105, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 11, 0, 0, 0, 98, 0, 0, 0, 1, 0, 0, 32, 2, 0, 0, 0, 1, 0, + 0, 32, 3, 0, 0, 0, 2, 0, 0, 16, 1, 0, 0, 0, 3, 0, 0, 48, 0, + 1, 0, 0, 200, 0, 0, 80, 3, 0, 0, 0, 0, 0, 0, 0, 244, 1, 0, 112, + 1, 246, 1, 0, 112, 1, 189, 2, 0, 96, 144, 178, 236, 250, 255, 255, 255, 255, 145, + 1, 0, 96, 144, 226, 33, 60, 222, 2, 0, 0, 189, 2, 0, 96, 0, 0, 0, 0, + 0, 0, 0, 0, 190, 2, 0, 16, 1, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 11, 0, + 0, 0, 98, 0, 0, 0, 1, 0, 0, 32, 2, 0, 0, 0, 1, 0, 0, 32, 3, + 0, 0, 0, 2, 0, 0, 16, 1, 0, 0, 0, 3, 0, 0, 48, 0, 1, 0, 0, + 200, 0, 0, 80, 3, 0, 0, 0, 0, 0, 0, 0, 244, 1, 0, 112, 1, 246, 1, + 0, 112, 1, 189, 2, 0, 96, 144, 178, 236, 250, 255, 255, 255, 255, 145, 1, 0, 96, + 144, 226, 33, 60, 222, 2, 0, 0, 189, 2, 0, 96, 0, 0, 0, 0, 0, 0, 0, + 0, 190, 2, 0, 16, 1, 0, 0, 0, +}; + +/* + * These tests don't have any assertions or expectations. They just try to parse garbage, to see if + * the result will be a crash. This is especially informative when run under Valgrind memcheck. + */ + +template <typename Message> void parse_garbage() { + for (int32_t ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + Message msg(ver); + const uint8_t* end = msgbuf + array_length(msgbuf); + for (size_t i = 0; i < array_length(msgbuf); ++i) { + const uint8_t* begin = msgbuf + i; + const uint8_t* p = begin; + msg.Deserialize(&p, end); + } + } + + time_t now = time(NULL); + std::cout << "Seeding rand() with " << now << " for fuzz test." << std::endl; + srand(now); + + // Fill large buffer with random bytes. + const int kBufSize = 10000; + UniquePtr<uint8_t[]> buf(new uint8_t[kBufSize]); + for (size_t i = 0; i < kBufSize; ++i) + buf[i] = static_cast<uint8_t>(rand()); + + for (uint32_t ver = 0; ver < MAX_MESSAGE_VERSION; ++ver) { + Message msg(ver); + const uint8_t* end = buf.get() + kBufSize; + for (size_t i = 0; i < kBufSize; ++i) { + const uint8_t* begin = buf.get() + i; + const uint8_t* p = begin; + msg.Deserialize(&p, end); + } + } +} +#if 0 +#define GARBAGE_TEST(Message) \ + TEST(GarbageTest, Message) { parse_garbage<Message>(); } + +GARBAGE_TEST(AbortOperationRequest); +GARBAGE_TEST(AbortOperationResponse); +GARBAGE_TEST(AddEntropyRequest); +GARBAGE_TEST(AddEntropyResponse); +GARBAGE_TEST(BeginOperationRequest); +GARBAGE_TEST(BeginOperationResponse); +GARBAGE_TEST(DeleteAllKeysRequest); +GARBAGE_TEST(DeleteAllKeysResponse); +GARBAGE_TEST(DeleteKeyRequest); +GARBAGE_TEST(DeleteKeyResponse); +GARBAGE_TEST(ExportKeyRequest); +GARBAGE_TEST(ExportKeyResponse); +GARBAGE_TEST(FinishOperationRequest); +GARBAGE_TEST(FinishOperationResponse); +GARBAGE_TEST(GenerateKeyRequest); +GARBAGE_TEST(GenerateKeyResponse); +GARBAGE_TEST(GetKeyCharacteristicsRequest); +GARBAGE_TEST(GetKeyCharacteristicsResponse); +GARBAGE_TEST(ImportKeyRequest); +GARBAGE_TEST(ImportKeyResponse); +GARBAGE_TEST(SupportedByAlgorithmAndPurposeRequest) +GARBAGE_TEST(SupportedByAlgorithmRequest) +GARBAGE_TEST(UpdateOperationRequest); +GARBAGE_TEST(UpdateOperationResponse); +GARBAGE_TEST(AttestKeyRequest); +GARBAGE_TEST(AttestKeyResponse); +GARBAGE_TEST(UpgradeKeyRequest); +GARBAGE_TEST(UpgradeKeyResponse); + +// The macro doesn't work on this one. +TEST(GarbageTest, SupportedResponse) { + parse_garbage<SupportedResponse<keymaster_digest_t>>(); +} +#endif +} // namespace test + +} // namespace keymaster diff --git a/unit_test/android_keymaster_test.cpp b/unit_test/android_keymaster_test.cpp new file mode 100644 index 0000000..d11b5be --- a/dev/null +++ b/unit_test/android_keymaster_test.cpp @@ -0,0 +1,3976 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fstream> +#include <string> +#include <vector> + +#include <openssl/evp.h> +#include <openssl/x509.h> + +#include <hardware/keymaster0.h> +#include <keymaster/key_factory.h> +#include <keymaster/soft_keymaster_context.h> +#include <keymaster/soft_keymaster_device.h> +#include <keymaster/softkeymaster.h> + +#include "android_keymaster_test_utils.h" +#include "attestation_record.h" +#include "keymaster0_engine.h" +#include "openssl_utils.h" + +#define CHECK_FAIL 1 +#define SUPPORT_TEST 1 +#define RSA_TEST 1 +#define EC_TEST 1 +#define AES_TEST 1 +#define HMAC_TEST 1 +#define MAX_TEST 1 +#define ENTROPY_TEST 1 +#define ATTESTATIONTEST 1 +#define KEYUPGRADETEST 0 +using std::ifstream; +using std::istreambuf_iterator; +using std::ofstream; +using std::string; +using std::unique_ptr; +using std::vector; + +extern "C" { +int __android_log_print(int prio, const char* tag, const char* fmt); +int __android_log_print(int prio, const char* tag, const char* fmt) { + (void)prio, (void)tag, (void)fmt; + return 0; +} +} // extern "C" + +namespace keymaster { +namespace test { + +const uint32_t kOsVersion = 060000; +const uint32_t kOsPatchLevel = 201603; + +StdoutLogger logger; + +template <typename T> vector<T> make_vector(const T* array, size_t len) { + return vector<T>(array, array + len); +} + +/** + * KeymasterEnforcement class for use in testing. It's permissive in the sense that it doesn't + * check cryptoperiods, but restrictive in the sense that the clock never advances (so rate-limited + * keys will only work once). + */ +class TestKeymasterEnforcement : public KeymasterEnforcement { + public: + TestKeymasterEnforcement() : KeymasterEnforcement(3, 3) {} + + virtual bool activation_date_valid(uint64_t /* activation_date */) const { return true; } + virtual bool expiration_date_passed(uint64_t /* expiration_date */) const { return false; } + virtual bool auth_token_timed_out(const hw_auth_token_t& /* token */, + uint32_t /* timeout */) const { + return false; + } + virtual uint32_t get_current_time() const { return 0; } + virtual bool ValidateTokenSignature(const hw_auth_token_t& /* token */) const { return true; } +}; + +/** + * Variant of SoftKeymasterContext that provides a TestKeymasterEnforcement. + */ +class TestKeymasterContext : public SoftKeymasterContext { + public: + TestKeymasterContext() {} + explicit TestKeymasterContext(const string& root_of_trust) : SoftKeymasterContext(root_of_trust) {} + + KeymasterEnforcement* enforcement_policy() override { return &test_policy_; } + + private: + TestKeymasterEnforcement test_policy_; +}; + +/** + * Test instance creator that builds a pure software keymaster2 implementation. + */ +class SoftKeymasterTestInstanceCreator : public Keymaster2TestInstanceCreator { + public: + keymaster2_device_t* CreateDevice() const override { + std::cerr << "Creating software-only device" << std::endl; + context_ = new TestKeymasterContext; + SoftKeymasterDevice* device = new SoftKeymasterDevice(context_); + AuthorizationSet version_info(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, kOsVersion) + .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel)); + device->keymaster2_device()->configure(device->keymaster2_device(), &version_info); + return device->keymaster2_device(); + } + + bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; } + int keymaster0_calls() const override { return 0; } + bool is_keymaster1_hw() const override { return false; } + KeymasterContext* keymaster_context() const override { return context_; } + + private: + mutable TestKeymasterContext* context_; +}; + +/** + * Test instance creator that builds a keymaster2 implementations. + */ +class AmlKeymasterTestInstanceCreator : public Keymaster2TestInstanceCreator { + public: + keymaster2_device_t* CreateDevice() const override { + const hw_module_t* mod; + keymaster2_device_t* device = NULL; + + int rc = hw_get_module_by_class(KEYSTORE_HARDWARE_MODULE_ID, NULL, &mod); + if (rc) { + std::cerr << "Could not find any keystore module!" << std::endl; + } else { + assert(mod->module_api_version >= KEYMASTER_MODULE_API_VERSION_2_0); + rc = keymaster2_open(mod, &device); + if (rc) { + std::cerr << "Error "<< rc << "opening keystore keymaster2 device" << std::endl; + return NULL; + } + } + + std::cerr << "Creating Amlogic keymaster2 device" << std::endl; + // context_ = new TestKeymasterContext; + // SoftKeymasterDevice* device = new SoftKeymasterDevice(context_); + AuthorizationSet version_info(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, kOsVersion) + .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel)); + device->configure(device, &version_info); + _device = device; + return device; + } + + bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; } + int keymaster0_calls() const override { return 0; } + bool is_keymaster1_hw() const override { return false; } + KeymasterContext* keymaster_context() const override { return (KeymasterContext*) _device; } + + private: + static keymaster2_device_t* _device; + //mutable TestKeymasterContext* context_; +}; + +keymaster2_device_t* AmlKeymasterTestInstanceCreator::_device; +/** + * Test instance creator that builds keymaster1 instances which wrap a faked hardware keymaster0 + * instance, with or without EC support. + */ +class Keymaster0AdapterTestInstanceCreator : public Keymaster2TestInstanceCreator { + public: + explicit Keymaster0AdapterTestInstanceCreator(bool support_ec) : support_ec_(support_ec) {} + + keymaster2_device_t* CreateDevice() const { + std::cerr << "Creating keymaster0-backed device (with ec: " << std::boolalpha << support_ec_ + << ")." << std::endl; + hw_device_t* softkeymaster_device; + EXPECT_EQ(0, openssl_open(&softkeymaster_module.common, KEYSTORE_KEYMASTER, + &softkeymaster_device)); + // Make the software device pretend to be hardware + keymaster0_device_t* keymaster0_device = + reinterpret_cast<keymaster0_device_t*>(softkeymaster_device); + keymaster0_device->flags &= ~KEYMASTER_SOFTWARE_ONLY; + + if (!support_ec_) { + // Make the software device pretend not to support EC + keymaster0_device->flags &= ~KEYMASTER_SUPPORTS_EC; + } + + counting_keymaster0_device_ = new Keymaster0CountingWrapper(keymaster0_device); + + context_ = new TestKeymasterContext; + SoftKeymasterDevice* keymaster = new SoftKeymasterDevice(context_); + keymaster->SetHardwareDevice(counting_keymaster0_device_); + AuthorizationSet version_info(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, kOsVersion) + .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel)); + keymaster->keymaster2_device()->configure(keymaster->keymaster2_device(), &version_info); + return keymaster->keymaster2_device(); + } + + bool algorithm_in_km0_hardware(keymaster_algorithm_t algorithm) const override { + switch (algorithm) { + case KM_ALGORITHM_RSA: + return true; + case KM_ALGORITHM_EC: + return support_ec_; + default: + return false; + } + } + int keymaster0_calls() const override { return counting_keymaster0_device_->count(); } + bool is_keymaster1_hw() const override { return false; } + KeymasterContext* keymaster_context() const override { return context_; } + + private: + mutable TestKeymasterContext* context_; + mutable Keymaster0CountingWrapper* counting_keymaster0_device_; + bool support_ec_; +}; + +/** + * Test instance creator that builds a SoftKeymasterDevice which wraps a fake hardware keymaster1 + * instance, with minimal digest support. + */ +class Sha256OnlyKeymaster2TestInstanceCreator : public Keymaster2TestInstanceCreator { + keymaster2_device_t* CreateDevice() const { + std::cerr << "Creating keymaster1-backed device that supports only SHA256"; + + // fake_device doesn't leak because device (below) takes ownership of it. + keymaster1_device_t* fake_device = make_device_sha256_only( + (new SoftKeymasterDevice(new TestKeymasterContext("PseudoHW")))->keymaster_device()); + + // device doesn't leak; it's cleaned up by device->keymaster_device()->common.close(). + context_ = new TestKeymasterContext; + SoftKeymasterDevice* device = new SoftKeymasterDevice(context_); + device->SetHardwareDevice(fake_device); + + AuthorizationSet version_info(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, kOsVersion) + .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel)); + device->keymaster2_device()->configure(device->keymaster2_device(), &version_info); + return device->keymaster2_device(); + } + + bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; } + int keymaster0_calls() const override { return 0; } + int minimal_digest_set() const override { return true; } + bool is_keymaster1_hw() const override { return true; } + KeymasterContext* keymaster_context() const override { return context_; } + + private: + mutable TestKeymasterContext* context_; +}; + +static auto test_params = testing::Values( +#if 0 + InstanceCreatorPtr(new SoftKeymasterTestInstanceCreator), + InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(true /* support_ec */)), + InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(false /* support_ec */)), + InstanceCreatorPtr(new Sha256OnlyKeymaster2TestInstanceCreator) +#endif + InstanceCreatorPtr(new AmlKeymasterTestInstanceCreator) + ); + +class NewKeyGeneration : public Keymaster2Test { + protected: + void CheckBaseParams() { + AuthorizationSet auths = sw_enforced(); + auths.Union(hw_enforced()); + EXPECT_GT(auths.SerializedSize(), 12U); + + EXPECT_TRUE(contains(auths, TAG_PURPOSE, KM_PURPOSE_SIGN)); + EXPECT_TRUE(contains(auths, TAG_PURPOSE, KM_PURPOSE_VERIFY)); + EXPECT_TRUE(contains(auths, TAG_USER_ID, 7)); + EXPECT_TRUE(contains(auths, TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)); + EXPECT_TRUE(contains(auths, TAG_AUTH_TIMEOUT, 300)); + + // Verify that App ID, App data and ROT are NOT included. + EXPECT_FALSE(contains(auths, TAG_ROOT_OF_TRUST)); + EXPECT_FALSE(contains(auths, TAG_APPLICATION_ID)); + EXPECT_FALSE(contains(auths, TAG_APPLICATION_DATA)); + + // Just for giggles, check that some unexpected tags/values are NOT present. + EXPECT_FALSE(contains(auths, TAG_PURPOSE, KM_PURPOSE_ENCRYPT)); + EXPECT_FALSE(contains(auths, TAG_PURPOSE, KM_PURPOSE_DECRYPT)); + EXPECT_FALSE(contains(auths, TAG_AUTH_TIMEOUT, 301)); + + // Now check that unspecified, defaulted tags are correct. + EXPECT_TRUE(contains(auths, KM_TAG_CREATION_DATETIME)); + if (GetParam()->is_keymaster1_hw()) { + // If the underlying (faked) HW is KM1, it will not have version info. + EXPECT_FALSE(auths.Contains(TAG_OS_VERSION)); + EXPECT_FALSE(auths.Contains(TAG_OS_PATCHLEVEL)); + } else { + // In all othe cases; SoftKeymasterDevice keys, or keymaster0 keys wrapped by + // SoftKeymasterDevice, version information will be present and up to date. + EXPECT_TRUE(contains(auths, TAG_OS_VERSION, kOsVersion)); + EXPECT_TRUE(contains(auths, TAG_OS_PATCHLEVEL, kOsPatchLevel)); + } + } +}; +INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, NewKeyGeneration, test_params); +#if RSA_TEST +TEST_P(NewKeyGeneration, Rsa) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE))); + CheckBaseParams(); + + // Check specified tags are all present, and in the right set. + AuthorizationSet crypto_params; + AuthorizationSet non_crypto_params; +#if 0 + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) { + EXPECT_NE(0U, hw_enforced().size()); + EXPECT_NE(0U, sw_enforced().size()); + crypto_params.push_back(hw_enforced()); + non_crypto_params.push_back(sw_enforced()); + } else { + EXPECT_EQ(0U, hw_enforced().size()); + EXPECT_NE(0U, sw_enforced().size()); + crypto_params.push_back(sw_enforced()); + } +#else + EXPECT_NE(0U, hw_enforced().size()); + EXPECT_NE(0U, sw_enforced().size()); + crypto_params.push_back(hw_enforced()); + non_crypto_params.push_back(sw_enforced()); +#endif + + EXPECT_TRUE(contains(crypto_params, TAG_ALGORITHM, KM_ALGORITHM_RSA)); + EXPECT_FALSE(contains(non_crypto_params, TAG_ALGORITHM, KM_ALGORITHM_RSA)); + EXPECT_TRUE(contains(crypto_params, TAG_KEY_SIZE, 256)); + EXPECT_FALSE(contains(non_crypto_params, TAG_KEY_SIZE, 256)); + EXPECT_TRUE(contains(crypto_params, TAG_RSA_PUBLIC_EXPONENT, 3)); + EXPECT_FALSE(contains(non_crypto_params, TAG_RSA_PUBLIC_EXPONENT, 3)); + + EXPECT_EQ(KM_ERROR_OK, DeleteKey()); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} +#endif +#if RSA_TEST +TEST_P(NewKeyGeneration, RsaDefaultSize) { + ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE, + GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3) + .SigningKey())); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +#if EC_TEST +TEST_P(NewKeyGeneration, Ecdsa) { + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE))); + CheckBaseParams(); + + // Check specified tags are all present, and in the right set. + AuthorizationSet crypto_params; + AuthorizationSet non_crypto_params; +#if 0 + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) { + EXPECT_NE(0U, hw_enforced().size()); + EXPECT_NE(0U, sw_enforced().size()); + crypto_params.push_back(hw_enforced()); + non_crypto_params.push_back(sw_enforced()); + } else { + EXPECT_EQ(0U, hw_enforced().size()); + EXPECT_NE(0U, sw_enforced().size()); + crypto_params.push_back(sw_enforced()); + } +#else + EXPECT_NE(0U, hw_enforced().size()); + EXPECT_NE(0U, sw_enforced().size()); + crypto_params.push_back(hw_enforced()); + non_crypto_params.push_back(sw_enforced()); +#endif + + EXPECT_TRUE(contains(crypto_params, TAG_ALGORITHM, KM_ALGORITHM_EC)); + EXPECT_FALSE(contains(non_crypto_params, TAG_ALGORITHM, KM_ALGORITHM_EC)); + EXPECT_TRUE(contains(crypto_params, TAG_KEY_SIZE, 224)); + EXPECT_FALSE(contains(non_crypto_params, TAG_KEY_SIZE, 224)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(1, GetParam()->keymaster0_calls()); +} +#endif +#if EC_TEST +TEST_P(NewKeyGeneration, EcdsaDefaultSize) { + ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE, + GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC) + .SigningKey() + .Digest(KM_DIGEST_NONE))); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(NewKeyGeneration, EcdsaInvalidSize) { + ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE, + GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(KM_DIGEST_NONE))); + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif + +#if EC_TEST +TEST_P(NewKeyGeneration, EcdsaMismatchKeySize) { + ASSERT_EQ(KM_ERROR_INVALID_ARGUMENT, + GenerateKey(AuthorizationSetBuilder() + .EcdsaSigningKey(224) + .Authorization(TAG_EC_CURVE, KM_EC_CURVE_P_256) + .Digest(KM_DIGEST_NONE))); +} +#endif + +#if EC_TEST +TEST_P(NewKeyGeneration, EcdsaAllValidSizes) { + size_t valid_sizes[] = {224, 256, 384, 521}; + for (size_t size : valid_sizes) { + EXPECT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(size).Digest( + KM_DIGEST_NONE))) + << "Failed to generate size: " << size; + } + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} +#endif +#if HMAC_TEST +TEST_P(NewKeyGeneration, HmacSha256) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 256))); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(NewKeyGeneration, HmacMultipleDigests) { + ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA1) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(NewKeyGeneration, HmacDigestNone) { + ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(NewKeyGeneration, HmacSha256TooShortMacLength) { + ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 48))); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(NewKeyGeneration, HmacSha256NonIntegralOctetMacLength) { + ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 130))); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(NewKeyGeneration, HmacSha256TooLongMacLength) { + ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 384))); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +typedef Keymaster2Test GetKeyCharacteristics; +INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, GetKeyCharacteristics, test_params); + +#if RSA_TEST +TEST_P(GetKeyCharacteristics, SimpleRsa) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE))); + AuthorizationSet original(sw_enforced()); + + ASSERT_EQ(KM_ERROR_OK, GetCharacteristics()); + EXPECT_EQ(original, sw_enforced()); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(1, GetParam()->keymaster0_calls()); +} +#endif +typedef Keymaster2Test SigningOperationsTest; +INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, SigningOperationsTest, test_params); +#if RSA_TEST +TEST_P(SigningOperationsTest, RsaSuccess) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE))); + string message = "12345678901234567890123456789012"; + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} +#endif +#if RSA_TEST +TEST_P(SigningOperationsTest, RsaPssSha256Success) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(768, 3) + .Digest(KM_DIGEST_SHA_2_256) + .Padding(KM_PAD_RSA_PSS))); + // Use large message, which won't work without digesting. + string message(1024, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(512, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE))); + string message = "12345678901234567890123456789012"; + string signature; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN); + EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE, BeginOperation(KM_PURPOSE_SIGN, begin_params)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, RsaPkcs1Sha256Success) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(512, 3) + .Digest(KM_DIGEST_SHA_2_256) + .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN))); + string message(1024, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} +#endif +#if RSA_TEST +TEST_P(SigningOperationsTest, RsaPkcs1NoDigestSuccess) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(512, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN))); + string message(53, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} +#endif +#if RSA_TEST +TEST_P(SigningOperationsTest, RsaPkcs1NoDigestTooLarge) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(512, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN))); + string message(54, 'a'); + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params)); + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + string signature; + EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&signature)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} +#endif +#if CHECK_FAIL +TEST_P(SigningOperationsTest, RsaPssSha256TooSmallKey) { + // Key must be at least 10 bytes larger than hash, to provide eight bytes of random salt, so + // verify that nine bytes larger than hash won't work. + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256 + 9 * 8, 3) + .Digest(KM_DIGEST_SHA_2_256) + .Padding(KM_PAD_RSA_PSS))); + string message(1024, 'a'); + string signature; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS); + EXPECT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_SIGN, begin_params)); +} +#endif +#if CHECK_FAIL +TEST_P(SigningOperationsTest, RsaNoPaddingHugeData) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN))); + string message(64 * 1024, 'a'); + string signature; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN); + ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params)); + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, UpdateOperation(message, &result, &input_consumed)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} +#endif +#if CHECK_FAIL +TEST_P(SigningOperationsTest, RsaAbort) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE))); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params)); + EXPECT_EQ(KM_ERROR_OK, AbortOperation()); + // Another abort should fail + EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, AbortOperation()); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} +#endif +#if RSA_TEST +TEST_P(SigningOperationsTest, RsaUnsupportedPadding) { + GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3) + .Digest(KM_DIGEST_SHA_2_256 /* supported digest */) + .Padding(KM_PAD_PKCS7)); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256); + ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, BeginOperation(KM_PURPOSE_SIGN, begin_params)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, RsaNoDigest) { + // PSS requires a digest. + GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_RSA_PSS)); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS); + ASSERT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_SIGN, begin_params)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, RsaNoPadding) { + // Padding must be specified + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaKey(256, 3).SigningKey().Digest( + KM_DIGEST_NONE))); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE); + ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, BeginOperation(KM_PURPOSE_SIGN, begin_params)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, RsaTooShortMessage) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE))); + string message = "1234567890123456789012345678901"; + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, RsaSignWithEncryptionKey) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaEncryptionKey(256, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE))); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE); + ASSERT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, BeginOperation(KM_PURPOSE_SIGN, begin_params)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, RsaSignTooLargeMessage) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE))); + string message(256 / 8, static_cast<char>(0xff)); + string signature; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE); + ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params)); + string result; + size_t input_consumed; + ASSERT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + ASSERT_EQ(message.size(), input_consumed); + string output; + ASSERT_EQ(KM_ERROR_INVALID_ARGUMENT, FinishOperation(&output)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} +#endif +#if EC_TEST +TEST_P(SigningOperationsTest, EcdsaSuccess) { + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE))); + string message(224 / 8, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} +#endif +#if EC_TEST +TEST_P(SigningOperationsTest, EcdsaSha256Success) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest( + KM_DIGEST_SHA_2_256))); + string message(1024, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_256); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, EcdsaSha384Success) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest( + KM_DIGEST_SHA_2_384))); + string message(1024, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_384); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, EcdsaNoPaddingHugeData) { + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE))); + string message(64 * 1024, 'a'); + string signature; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE); + ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params)); + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, EcdsaAllSizesAndHashes) { + vector<int> key_sizes = {224, 256, 384, 521}; + vector<keymaster_digest_t> digests = { + KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224, KM_DIGEST_SHA_2_256, + KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512, + }; + + for (int key_size : key_sizes) { + for (keymaster_digest_t digest : digests) { + ASSERT_EQ( + KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(key_size).Digest(digest))); + + string message(1024, 'a'); + string signature; + if (digest == KM_DIGEST_NONE) + message.resize(key_size / 8); + SignMessage(message, &signature, digest); + } + } + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(digests.size() * key_sizes.size() * 3, + static_cast<size_t>(GetParam()->keymaster0_calls())); +} +#endif +#if AES_TEST +TEST_P(SigningOperationsTest, AesEcbSign) { + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().AesEncryptionKey(128).Authorization( + TAG_BLOCK_MODE, KM_MODE_ECB))); + ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_SIGN)); + ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_VERIFY)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +#if HMAC_TEST +TEST_P(SigningOperationsTest, HmacSha1Success) { + if (GetParam()->minimal_digest_set()) + // Can't emulate other digests for HMAC. + return; + + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA1) + .Authorization(TAG_MIN_MAC_LENGTH, 160)); + string message = "12345678901234567890123456789012"; + string signature; + MacMessage(message, &signature, 160); + ASSERT_EQ(20U, signature.size()); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +#if HMAC_TEST +TEST_P(SigningOperationsTest, HmacSha224Success) { + if (GetParam()->minimal_digest_set()) + // Can't emulate other digests for HMAC. + return; + + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_224) + .Authorization(TAG_MIN_MAC_LENGTH, 160))); + string message = "12345678901234567890123456789012"; + string signature; + MacMessage(message, &signature, 224); + ASSERT_EQ(28U, signature.size()); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, HmacSha256Success) { + if (GetParam()->minimal_digest_set()) + // Can't emulate other digests for HMAC. + return; + + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 256))); + string message = "12345678901234567890123456789012"; + string signature; + MacMessage(message, &signature, 256); + ASSERT_EQ(32U, signature.size()); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, HmacSha384Success) { + if (GetParam()->minimal_digest_set()) + // Can't emulate other digests for HMAC. + return; + + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_384) + .Authorization(TAG_MIN_MAC_LENGTH, 384))); + + string message = "12345678901234567890123456789012"; + string signature; + MacMessage(message, &signature, 384); + ASSERT_EQ(48U, signature.size()); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, HmacSha512Success) { + if (GetParam()->minimal_digest_set()) + // Can't emulate other digests for HMAC. + return; + + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_512) + .Authorization(TAG_MIN_MAC_LENGTH, 384))); + string message = "12345678901234567890123456789012"; + string signature; + MacMessage(message, &signature, 512); + ASSERT_EQ(64U, signature.size()); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, HmacLengthInKey) { + // TODO(swillden): unified API should generate an error on key generation. + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + string message = "12345678901234567890123456789012"; + string signature; + MacMessage(message, &signature, 160); + ASSERT_EQ(20U, signature.size()); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, HmacRfc4231TestCase1) { + uint8_t key_data[] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + }; + string message = "Hi There"; + uint8_t sha_224_expected[] = { + 0x89, 0x6f, 0xb1, 0x12, 0x8a, 0xbb, 0xdf, 0x19, 0x68, 0x32, 0x10, 0x7c, 0xd4, 0x9d, + 0xf3, 0x3f, 0x47, 0xb4, 0xb1, 0x16, 0x99, 0x12, 0xba, 0x4f, 0x53, 0x68, 0x4b, 0x22, + }; + uint8_t sha_256_expected[] = { + 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, + 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, + 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7, + }; + uint8_t sha_384_expected[] = { + 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62, 0x6b, 0x08, 0x25, 0xf4, + 0xab, 0x46, 0x90, 0x7f, 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6, + 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c, 0xfa, 0xea, 0x9e, 0xa9, + 0x07, 0x6e, 0xde, 0x7f, 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6, + }; + uint8_t sha_512_expected[] = { + 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, 0x4f, 0xf0, 0xb4, 0x24, 0x1a, + 0x1d, 0x6c, 0xb0, 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78, 0x7a, 0xd0, + 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde, 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, + 0x02, 0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4, 0xbe, 0x9d, 0x91, 0x4e, + 0xeb, 0x61, 0xf1, 0x70, 0x2e, 0x69, 0x6c, 0x20, 0x3a, 0x12, 0x68, 0x54, + }; + + string key = make_string(key_data); + + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected)); + if (!GetParam()->minimal_digest_set()) { + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected)); + } + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, HmacRfc4231TestCase2) { + string key = "Jefe"; + string message = "what do ya want for nothing?"; + uint8_t sha_224_expected[] = { + 0xa3, 0x0e, 0x01, 0x09, 0x8b, 0xc6, 0xdb, 0xbf, 0x45, 0x69, 0x0f, 0x3a, 0x7e, 0x9e, + 0x6d, 0x0f, 0x8b, 0xbe, 0xa2, 0xa3, 0x9e, 0x61, 0x48, 0x00, 0x8f, 0xd0, 0x5e, 0x44, + }; + uint8_t sha_256_expected[] = { + 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, + 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, + 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43, + }; + uint8_t sha_384_expected[] = { + 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31, 0x61, 0x7f, 0x78, 0xd2, + 0xb5, 0x8a, 0x6b, 0x1b, 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47, + 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e, 0x8e, 0x22, 0x40, 0xca, + 0x5e, 0x69, 0xe2, 0xc7, 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49, + }; + uint8_t sha_512_expected[] = { + 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, 0xe3, 0x95, 0xfb, 0xe7, 0x3b, + 0x56, 0xe0, 0xa3, 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6, 0x10, 0x27, + 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54, 0x97, 0x58, 0xbf, 0x75, 0xc0, 0x5a, 0x99, + 0x4a, 0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd, 0xca, 0xea, 0xb1, 0xa3, + 0x4d, 0x4a, 0x6b, 0x4b, 0x63, 0x6e, 0x07, 0x0a, 0x38, 0xbc, 0xe7, 0x37, + }; + + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected)); + if (!GetParam()->minimal_digest_set()) { + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected)); + } + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, HmacRfc4231TestCase3) { + string key(20, 0xaa); + string message(50, 0xdd); + uint8_t sha_224_expected[] = { + 0x7f, 0xb3, 0xcb, 0x35, 0x88, 0xc6, 0xc1, 0xf6, 0xff, 0xa9, 0x69, 0x4d, 0x7d, 0x6a, + 0xd2, 0x64, 0x93, 0x65, 0xb0, 0xc1, 0xf6, 0x5d, 0x69, 0xd1, 0xec, 0x83, 0x33, 0xea, + }; + uint8_t sha_256_expected[] = { + 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, + 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, + 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe, + }; + uint8_t sha_384_expected[] = { + 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, 0x0a, 0xa2, 0xac, 0xe0, + 0x14, 0xc8, 0xa8, 0x6f, 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb, + 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, 0x2a, 0x5a, 0xb3, 0x9d, + 0xc1, 0x38, 0x14, 0xb9, 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27, + }; + uint8_t sha_512_expected[] = { + 0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, 0xef, 0xb0, 0xf0, 0x75, 0x6c, + 0x89, 0x0b, 0xe9, 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, 0x55, 0xf8, + 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, 0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22, + 0xc8, 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07, 0xb9, 0x46, 0xa3, 0x37, + 0xbe, 0xe8, 0x94, 0x26, 0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb, + }; + + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected)); + if (!GetParam()->minimal_digest_set()) { + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected)); + } + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, HmacRfc4231TestCase4) { + uint8_t key_data[25] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + }; + string key = make_string(key_data); + string message(50, 0xcd); + uint8_t sha_224_expected[] = { + 0x6c, 0x11, 0x50, 0x68, 0x74, 0x01, 0x3c, 0xac, 0x6a, 0x2a, 0xbc, 0x1b, 0xb3, 0x82, + 0x62, 0x7c, 0xec, 0x6a, 0x90, 0xd8, 0x6e, 0xfc, 0x01, 0x2d, 0xe7, 0xaf, 0xec, 0x5a, + }; + uint8_t sha_256_expected[] = { + 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, + 0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, + 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b, + }; + uint8_t sha_384_expected[] = { + 0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85, 0x19, 0x33, 0xab, 0x62, + 0x90, 0xaf, 0x6c, 0xa7, 0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c, + 0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e, 0x68, 0x01, 0xdd, 0x23, + 0xc4, 0xa7, 0xd6, 0x79, 0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb, + }; + uint8_t sha_512_expected[] = { + 0xb0, 0xba, 0x46, 0x56, 0x37, 0x45, 0x8c, 0x69, 0x90, 0xe5, 0xa8, 0xc5, 0xf6, + 0x1d, 0x4a, 0xf7, 0xe5, 0x76, 0xd9, 0x7f, 0xf9, 0x4b, 0x87, 0x2d, 0xe7, 0x6f, + 0x80, 0x50, 0x36, 0x1e, 0xe3, 0xdb, 0xa9, 0x1c, 0xa5, 0xc1, 0x1a, 0xa2, 0x5e, + 0xb4, 0xd6, 0x79, 0x27, 0x5c, 0xc5, 0x78, 0x80, 0x63, 0xa5, 0xf1, 0x97, 0x41, + 0x12, 0x0c, 0x4f, 0x2d, 0xe2, 0xad, 0xeb, 0xeb, 0x10, 0xa2, 0x98, 0xdd, + }; + + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected)); + if (!GetParam()->minimal_digest_set()) { + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected)); + } + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, HmacRfc4231TestCase5) { + string key(20, 0x0c); + string message = "Test With Truncation"; + + uint8_t sha_224_expected[] = { + 0x0e, 0x2a, 0xea, 0x68, 0xa9, 0x0c, 0x8d, 0x37, + 0xc9, 0x88, 0xbc, 0xdb, 0x9f, 0xca, 0x6f, 0xa8, + }; + uint8_t sha_256_expected[] = { + 0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0, + 0x6e, 0x0c, 0x79, 0x6c, 0x29, 0x55, 0x55, 0x2b, + }; + uint8_t sha_384_expected[] = { + 0x3a, 0xbf, 0x34, 0xc3, 0x50, 0x3b, 0x2a, 0x23, + 0xa4, 0x6e, 0xfc, 0x61, 0x9b, 0xae, 0xf8, 0x97, + }; + uint8_t sha_512_expected[] = { + 0x41, 0x5f, 0xad, 0x62, 0x71, 0x58, 0x0a, 0x53, + 0x1d, 0x41, 0x79, 0xbc, 0x89, 0x1d, 0x87, 0xa6, + }; + + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected)); + if (!GetParam()->minimal_digest_set()) { + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected)); + } + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif + +#if HMAC_TEST +TEST_P(SigningOperationsTest, HmacRfc4231TestCase6) { + string key(131, 0xaa); + string message = "Test Using Larger Than Block-Size Key - Hash Key First"; + + uint8_t sha_224_expected[] = { + 0x95, 0xe9, 0xa0, 0xdb, 0x96, 0x20, 0x95, 0xad, 0xae, 0xbe, 0x9b, 0x2d, 0x6f, 0x0d, + 0xbc, 0xe2, 0xd4, 0x99, 0xf1, 0x12, 0xf2, 0xd2, 0xb7, 0x27, 0x3f, 0xa6, 0x87, 0x0e, + }; + uint8_t sha_256_expected[] = { + 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, + 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, + 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54, + }; + uint8_t sha_384_expected[] = { + 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, 0x88, 0xd2, 0xc6, 0x3a, + 0x04, 0x1b, 0xc5, 0xb4, 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f, + 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, 0x0c, 0x2e, 0xf6, 0xab, + 0x40, 0x30, 0xfe, 0x82, 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52, + }; + uint8_t sha_512_expected[] = { + 0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, 0xb7, 0x14, 0x93, 0xc1, 0xdd, + 0x7b, 0xe8, 0xb4, 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1, 0x12, 0x1b, + 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25, + 0x98, 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52, 0x95, 0xe6, 0x4f, 0x73, + 0xf6, 0x3f, 0x0a, 0xec, 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98, + }; + + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected)); + if (!GetParam()->minimal_digest_set()) { + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected)); + } + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif + +#if HMAC_TEST +TEST_P(SigningOperationsTest, HmacRfc4231TestCase7) { + string key(131, 0xaa); + string message = "This is a test using a larger than block-size key and a larger than " + "block-size data. The key needs to be hashed before being used by the HMAC " + "algorithm."; + + uint8_t sha_224_expected[] = { + 0x3a, 0x85, 0x41, 0x66, 0xac, 0x5d, 0x9f, 0x02, 0x3f, 0x54, 0xd5, 0x17, 0xd0, 0xb3, + 0x9d, 0xbd, 0x94, 0x67, 0x70, 0xdb, 0x9c, 0x2b, 0x95, 0xc9, 0xf6, 0xf5, 0x65, 0xd1, + }; + uint8_t sha_256_expected[] = { + 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, + 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, + 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2, + }; + uint8_t sha_384_expected[] = { + 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, 0x35, 0x1e, 0x2f, 0x25, + 0x4e, 0x8f, 0xd3, 0x2c, 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a, + 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, 0xa6, 0x78, 0xcc, 0x31, + 0xe7, 0x99, 0x17, 0x6d, 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e, + }; + uint8_t sha_512_expected[] = { + 0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, 0xa4, 0xdf, 0xa9, 0xf9, 0x6e, + 0x5e, 0x3f, 0xfd, 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86, 0x5d, 0xf5, + 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82, + 0xb1, 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15, 0x13, 0x46, 0x76, 0xfb, + 0x6d, 0xe0, 0x44, 0x60, 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58, + }; + + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected)); + if (!GetParam()->minimal_digest_set()) { + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected)); + CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected)); + } + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, HmacSha256TooLargeMacLength) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 256))); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_MAC_LENGTH, 264); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256); + ASSERT_EQ(KM_ERROR_UNSUPPORTED_MAC_LENGTH, + BeginOperation(KM_PURPOSE_SIGN, begin_params, nullptr /* output_params */)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(SigningOperationsTest, HmacSha256TooSmallMacLength) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_MAC_LENGTH, 120); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256); + ASSERT_EQ(KM_ERROR_INVALID_MAC_LENGTH, + BeginOperation(KM_PURPOSE_SIGN, begin_params, nullptr /* output_params */)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +// TODO(swillden): Add more verification failure tests. + +typedef Keymaster2Test VerificationOperationsTest; +INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, VerificationOperationsTest, test_params); +#if RSA_TEST +TEST_P(VerificationOperationsTest, RsaSuccess) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE))); + string message = "12345678901234567890123456789012"; + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE); + VerifyMessage(message, signature, KM_DIGEST_NONE, KM_PAD_NONE); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(VerificationOperationsTest, RsaPssSha256Success) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(768, 3) + .Digest(KM_DIGEST_SHA_2_256) + .Padding(KM_PAD_RSA_PSS))); + // Use large message, which won't work without digesting. + string message(1024, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS); + VerifyMessage(message, signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(VerificationOperationsTest, RsaPssSha224Success) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(512, 3) + .Digest(KM_DIGEST_SHA_2_224) + .Padding(KM_PAD_RSA_PSS))); + // Use large message, which won't work without digesting. + string message(1024, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PSS); + VerifyMessage(message, signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PSS); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); + + // Verify with OpenSSL. + string pubkey; + EXPECT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &pubkey)); + + const uint8_t* p = reinterpret_cast<const uint8_t*>(pubkey.data()); + unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey( + d2i_PUBKEY(nullptr /* alloc new */, &p, pubkey.size())); + ASSERT_TRUE(pkey.get()); + + EVP_MD_CTX digest_ctx; + EVP_MD_CTX_init(&digest_ctx); + EVP_PKEY_CTX* pkey_ctx; + EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, EVP_sha224(), nullptr /* engine */, + pkey.get())); + EXPECT_EQ(1, EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING)); + EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), message.size())); + EXPECT_EQ(1, + EVP_DigestVerifyFinal(&digest_ctx, reinterpret_cast<const uint8_t*>(signature.data()), + signature.size())); + EVP_MD_CTX_cleanup(&digest_ctx); +} + +TEST_P(VerificationOperationsTest, RsaPssSha256CorruptSignature) { + GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(768, 3) + .Digest(KM_DIGEST_SHA_2_256) + .Padding(KM_PAD_RSA_PSS)); + string message(1024, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS); + ++signature[signature.size() / 2]; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params)); + + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(VerificationOperationsTest, RsaPssSha256CorruptInput) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(768, 3) + .Digest(KM_DIGEST_SHA_2_256) + .Padding(KM_PAD_RSA_PSS))); + // Use large message, which won't work without digesting. + string message(1024, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS); + ++message[message.size() / 2]; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params)); + + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(VerificationOperationsTest, RsaPkcs1Sha256Success) { + GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(512, 3) + .Digest(KM_DIGEST_SHA_2_256) + .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)); + string message(1024, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN); + VerifyMessage(message, signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(VerificationOperationsTest, RsaPks1Sha224Success) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(512, 3) + .Digest(KM_DIGEST_SHA_2_224) + .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN))); + // Use large message, which won't work without digesting. + string message(1024, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PKCS1_1_5_SIGN); + VerifyMessage(message, signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PKCS1_1_5_SIGN); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); + + // Verify with OpenSSL. + string pubkey; + EXPECT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &pubkey)); + + const uint8_t* p = reinterpret_cast<const uint8_t*>(pubkey.data()); + unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey( + d2i_PUBKEY(nullptr /* alloc new */, &p, pubkey.size())); + ASSERT_TRUE(pkey.get()); + + EVP_MD_CTX digest_ctx; + EVP_MD_CTX_init(&digest_ctx); + EVP_PKEY_CTX* pkey_ctx; + EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, EVP_sha224(), nullptr /* engine */, + pkey.get())); + EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), message.size())); + EXPECT_EQ(1, + EVP_DigestVerifyFinal(&digest_ctx, reinterpret_cast<const uint8_t*>(signature.data()), + signature.size())); + EVP_MD_CTX_cleanup(&digest_ctx); +} + +TEST_P(VerificationOperationsTest, RsaPkcs1Sha256CorruptSignature) { + GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(512, 3) + .Digest(KM_DIGEST_SHA_2_256) + .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)); + string message(1024, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN); + ++signature[signature.size() / 2]; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params)); + + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(VerificationOperationsTest, RsaPkcs1Sha256CorruptInput) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(512, 3) + .Digest(KM_DIGEST_SHA_2_256) + .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN))); + // Use large message, which won't work without digesting. + string message(1024, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN); + ++message[message.size() / 2]; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params)); + + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} +#endif +#if CHECK_FAIL +TEST_P(VerificationOperationsTest, RsaAllDigestAndPadCombinations) { + vector<keymaster_digest_t> digests = { + KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224, + KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512, + }; + + vector<keymaster_padding_t> padding_modes{ + KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN, KM_PAD_RSA_PSS, + }; + + int trial_count = 0; + for (keymaster_padding_t padding_mode : padding_modes) { + for (keymaster_digest_t digest : digests) { + if (digest != KM_DIGEST_NONE && padding_mode == KM_PAD_NONE) + // Digesting requires padding + continue; + + // Compute key & message size that will work. + size_t key_bits = 0; + size_t message_len = 1000; + + if (digest == KM_DIGEST_NONE) { + key_bits = 256; + switch (padding_mode) { + case KM_PAD_NONE: + // Match key size. + message_len = key_bits / 8; + break; + case KM_PAD_RSA_PKCS1_1_5_SIGN: + message_len = key_bits / 8 - 11; + break; + case KM_PAD_RSA_PSS: + // PSS requires a digest. + continue; + default: + FAIL() << "Missing padding"; + break; + } + } else { + size_t digest_bits; + switch (digest) { + case KM_DIGEST_MD5: + digest_bits = 128; + break; + case KM_DIGEST_SHA1: + digest_bits = 160; + break; + case KM_DIGEST_SHA_2_224: + digest_bits = 224; + break; + case KM_DIGEST_SHA_2_256: + digest_bits = 256; + break; + case KM_DIGEST_SHA_2_384: + digest_bits = 384; + break; + case KM_DIGEST_SHA_2_512: + digest_bits = 512; + break; + default: + FAIL() << "Missing digest"; + } + + switch (padding_mode) { + case KM_PAD_RSA_PKCS1_1_5_SIGN: + key_bits = digest_bits + 8 * (11 + 19); + break; + case KM_PAD_RSA_PSS: + key_bits = digest_bits * 2 + 2 * 8; + break; + default: + FAIL() << "Missing padding"; + break; + } + } + + // round up to 128 bits because new boringssl supports only 128 bit mulitples + key_bits += 127; + key_bits &= ~127; + GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(key_bits, 3) + .Digest(digest) + .Padding(padding_mode)); + string message(message_len, 'a'); + string signature; + SignMessage(message, &signature, digest, padding_mode); + VerifyMessage(message, signature, digest, padding_mode); + ++trial_count; + } + } + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(trial_count * 4, GetParam()->keymaster0_calls()); +} +#endif +#if EC_TEST +TEST_P(VerificationOperationsTest, EcdsaSuccess) { + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE))); + string message = "12345678901234567890123456789012"; + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE); + VerifyMessage(message, signature, KM_DIGEST_NONE); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(VerificationOperationsTest, EcdsaTooShort) { + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE))); + string message = "12345678901234567890"; + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE); + VerifyMessage(message, signature, KM_DIGEST_NONE); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(VerificationOperationsTest, EcdsaSlightlyTooLong) { + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(521).Digest(KM_DIGEST_NONE))); + + string message(66, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE); + VerifyMessage(message, signature, KM_DIGEST_NONE); + + // Modifying low-order bits doesn't matter, because they didn't get signed. Ugh. + message[65] ^= 7; + VerifyMessage(message, signature, KM_DIGEST_NONE); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(5, GetParam()->keymaster0_calls()); +} + +TEST_P(VerificationOperationsTest, EcdsaSha256Success) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .EcdsaSigningKey(256) + .Digest(KM_DIGEST_SHA_2_256) + .Digest(KM_DIGEST_NONE))); + string message = "12345678901234567890123456789012"; + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_256); + VerifyMessage(message, signature, KM_DIGEST_SHA_2_256); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); + + // Just for giggles, try verifying with the wrong digest. + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params)); + + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result)); +} + +TEST_P(VerificationOperationsTest, EcdsaSha224Success) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest( + KM_DIGEST_SHA_2_224))); + + string message = "12345678901234567890123456789012"; + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_224); + VerifyMessage(message, signature, KM_DIGEST_SHA_2_224); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); + + // Just for giggles, try verifying with the wrong digest. + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params)); + + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result)); +} + +TEST_P(VerificationOperationsTest, EcdsaAllDigestsAndKeySizes) { + keymaster_digest_t digests[] = { + KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224, KM_DIGEST_SHA_2_256, + KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512, + }; + size_t key_sizes[] = {224, 256, 384, 521}; + + string message = "1234567890"; + string signature; + + for (auto key_size : key_sizes) { + AuthorizationSetBuilder builder; + builder.EcdsaSigningKey(key_size); + for (auto digest : digests) + builder.Digest(digest); + ASSERT_EQ(KM_ERROR_OK, GenerateKey(builder)); + + for (auto digest : digests) { + SignMessage(message, &signature, digest); + VerifyMessage(message, signature, digest); + } + } + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(static_cast<int>(array_length(key_sizes) * (1 + 3 * array_length(digests))), + GetParam()->keymaster0_calls()); +} +#endif +#if HMAC_TEST +TEST_P(VerificationOperationsTest, HmacSha1Success) { + if (GetParam()->minimal_digest_set()) + // Can't emulate missing digests for HMAC. + return; + + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA1) + .Authorization(TAG_MIN_MAC_LENGTH, 128)); + string message = "123456789012345678901234567890123456789012345678"; + string signature; + MacMessage(message, &signature, 160); + VerifyMac(message, signature); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(VerificationOperationsTest, HmacSha224Success) { + if (GetParam()->minimal_digest_set()) + // Can't emulate missing digests for HMAC. + return; + + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_224) + .Authorization(TAG_MIN_MAC_LENGTH, 128)); + string message = "123456789012345678901234567890123456789012345678"; + string signature; + MacMessage(message, &signature, 224); + VerifyMac(message, signature); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(VerificationOperationsTest, HmacSha256Success) { + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 128)); + string message = "123456789012345678901234567890123456789012345678"; + string signature; + MacMessage(message, &signature, 256); + VerifyMac(message, signature); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(VerificationOperationsTest, HmacSha256TooShortMac) { + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 128)); + string message = "123456789012345678901234567890123456789012345678"; + string signature; + MacMessage(message, &signature, 256); + + // Shorten to 128 bits, should still work. + signature.resize(128 / 8); + VerifyMac(message, signature); + + // Drop one more byte. + signature.resize(signature.length() - 1); + + AuthorizationSet begin_params(client_params()); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params)); + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH, FinishOperation(signature, &result)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(VerificationOperationsTest, HmacSha384Success) { + if (GetParam()->minimal_digest_set()) + // Can't emulate missing digests for HMAC. + return; + + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_384) + .Authorization(TAG_MIN_MAC_LENGTH, 128)); + string message = "123456789012345678901234567890123456789012345678"; + string signature; + MacMessage(message, &signature, 384); + VerifyMac(message, signature); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(VerificationOperationsTest, HmacSha512Success) { + if (GetParam()->minimal_digest_set()) + // Can't emulate missing digests for HMAC. + return; + + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_512) + .Authorization(TAG_MIN_MAC_LENGTH, 128)); + string message = "123456789012345678901234567890123456789012345678"; + string signature; + MacMessage(message, &signature, 512); + VerifyMac(message, signature); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +typedef Keymaster2Test ExportKeyTest; +INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, ExportKeyTest, test_params); +#if RSA_TEST +TEST_P(ExportKeyTest, RsaSuccess) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE))); + string export_data; + ASSERT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &export_data)); + EXPECT_GT(export_data.length(), 0U); + + // TODO(swillden): Verify that the exported key is actually usable to verify signatures. + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} +#endif +#if EC_TEST +TEST_P(ExportKeyTest, EcdsaSuccess) { + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE))); + string export_data; + ASSERT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &export_data)); + EXPECT_GT(export_data.length(), 0U); + + // TODO(swillden): Verify that the exported key is actually usable to verify signatures. + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} +#endif +#if RSA_TEST +TEST_P(ExportKeyTest, RsaUnsupportedKeyFormat) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE))); + string export_data; + ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_PKCS8, &export_data)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} + +TEST_P(ExportKeyTest, RsaCorruptedKeyBlob) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE))); + corrupt_key_blob(); + string export_data; + ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, ExportKey(KM_KEY_FORMAT_X509, &export_data)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} +#endif +#if AES_TEST +TEST_P(ExportKeyTest, AesKeyExportFails) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().AesEncryptionKey(128))); + string export_data; + + EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_X509, &export_data)); + EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_PKCS8, &export_data)); + EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_RAW, &export_data)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +static string read_file(const string& file_name) { + ifstream file_stream(file_name, std::ios::binary); + istreambuf_iterator<char> file_begin(file_stream); + istreambuf_iterator<char> file_end; + return string(file_begin, file_end); +} + +typedef Keymaster2Test ImportKeyTest; +INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, ImportKeyTest, test_params); +#if RSA_TEST +TEST_P(ImportKeyTest, RsaSuccess) { + string pk8_key = read_file("rsa_privkey_pk8.der"); + ASSERT_EQ(633U, pk8_key.size()); + + ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder() + .RsaSigningKey(1024, 65537) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE), + KM_KEY_FORMAT_PKCS8, pk8_key)); + + // Check values derived from the key. + EXPECT_TRUE(contains(hw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA)); + EXPECT_TRUE(contains(hw_enforced(), TAG_KEY_SIZE, 1024)); + EXPECT_TRUE(contains(hw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 65537U)); + + // And values provided by AndroidKeymaster + EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED)); + EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME)); + + string message(1024 / 8, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE); + VerifyMessage(message, signature, KM_DIGEST_NONE, KM_PAD_NONE); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} +#endif +#if RSA_TEST +TEST_P(ImportKeyTest, RsaKeySizeMismatch) { + string pk8_key = read_file("rsa_privkey_pk8.der"); + ASSERT_EQ(633U, pk8_key.size()); + ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH, + ImportKey(AuthorizationSetBuilder() + .RsaSigningKey(2048 /* Doesn't match key */, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE), + KM_KEY_FORMAT_PKCS8, pk8_key)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(ImportKeyTest, RsaPublicExponenMismatch) { + string pk8_key = read_file("rsa_privkey_pk8.der"); + ASSERT_EQ(633U, pk8_key.size()); + ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH, + ImportKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3 /* Doesnt' match key */) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE), + KM_KEY_FORMAT_PKCS8, pk8_key)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +#if EC_TEST +TEST_P(ImportKeyTest, EcdsaSuccess) { + string pk8_key = read_file("ec_privkey_pk8.der"); + ASSERT_EQ(138U, pk8_key.size()); + + ASSERT_EQ(KM_ERROR_OK, + ImportKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE), + KM_KEY_FORMAT_PKCS8, pk8_key)); + + // Check values derived from the key. + EXPECT_TRUE(contains(hw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_EC)); + EXPECT_TRUE(contains(hw_enforced(), TAG_KEY_SIZE, 256)); + + // And values provided by AndroidKeymaster + EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED)); + EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME)); + + string message(32, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE); + VerifyMessage(message, signature, KM_DIGEST_NONE); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(ImportKeyTest, EcdsaSizeSpecified) { + string pk8_key = read_file("ec_privkey_pk8.der"); + ASSERT_EQ(138U, pk8_key.size()); + + ASSERT_EQ(KM_ERROR_OK, + ImportKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE), + KM_KEY_FORMAT_PKCS8, pk8_key)); + + // Check values derived from the key. + EXPECT_TRUE(contains(hw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_EC)); + EXPECT_TRUE(contains(hw_enforced(), TAG_KEY_SIZE, 256)); + + // And values provided by AndroidKeymaster + EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED)); + EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME)); + + string message(32, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE); + VerifyMessage(message, signature, KM_DIGEST_NONE); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(ImportKeyTest, EcdsaSizeMismatch) { + string pk8_key = read_file("ec_privkey_pk8.der"); + ASSERT_EQ(138U, pk8_key.size()); + ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH, + ImportKey(AuthorizationSetBuilder() + .EcdsaSigningKey(224 /* Doesn't match key */) + .Digest(KM_DIGEST_NONE), + KM_KEY_FORMAT_PKCS8, pk8_key)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +#if AES_TEST +TEST_P(ImportKeyTest, AesKeySuccess) { + char key_data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + string key(key_data, sizeof(key_data)); + ASSERT_EQ(KM_ERROR_OK, + ImportKey(AuthorizationSetBuilder().AesEncryptionKey(128).EcbMode().Authorization( + TAG_PADDING, KM_PAD_PKCS7), + KM_KEY_FORMAT_RAW, key)); + + EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED)); + EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME)); + + string message = "Hello World!"; + string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_PKCS7); + string plaintext = DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_PKCS7); + EXPECT_EQ(message, plaintext); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +#if HMAC_TEST +TEST_P(ImportKeyTest, HmacSha256KeySuccess) { + char key_data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + string key(key_data, sizeof(key_data)); + ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder() + .HmacKey(sizeof(key_data) * 8) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 256), + KM_KEY_FORMAT_RAW, key)); + + EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED)); + EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME)); + + string message = "Hello World!"; + string signature; + MacMessage(message, &signature, 256); + VerifyMac(message, signature); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +typedef Keymaster2Test EncryptionOperationsTest; +INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, EncryptionOperationsTest, test_params); +#if RSA_TEST +TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) { + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE))); + + string message = "12345678901234567890123456789012"; + string ciphertext1 = EncryptMessage(string(message), KM_PAD_NONE); + EXPECT_EQ(256U / 8, ciphertext1.size()); + + string ciphertext2 = EncryptMessage(string(message), KM_PAD_NONE); + EXPECT_EQ(256U / 8, ciphertext2.size()); + + // Unpadded RSA is deterministic + EXPECT_EQ(ciphertext1, ciphertext2); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, RsaNoPaddingTooShort) { + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE))); + + string message = "1"; + + string ciphertext = EncryptMessage(message, KM_PAD_NONE); + EXPECT_EQ(256U / 8, ciphertext.size()); + + string expected_plaintext = string(256 / 8 - 1, 0) + message; + string plaintext = DecryptMessage(ciphertext, KM_PAD_NONE); + + EXPECT_EQ(expected_plaintext, plaintext); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLong) { + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE))); + + string message = "123456789012345678901234567890123"; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, UpdateOperation(message, &result, &input_consumed)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, RsaNoPaddingLargerThanModulus) { + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE))); + + string exported; + ASSERT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &exported)); + + const uint8_t* p = reinterpret_cast<const uint8_t*>(exported.data()); + unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey( + d2i_PUBKEY(nullptr /* alloc new */, &p, exported.size())); + unique_ptr<RSA, RSA_Delete> rsa(EVP_PKEY_get1_RSA(pkey.get())); + + size_t modulus_len = BN_num_bytes(rsa->n); + ASSERT_EQ(256U / 8, modulus_len); + unique_ptr<uint8_t[]> modulus_buf(new uint8_t[modulus_len]); + BN_bn2bin(rsa->n, modulus_buf.get()); + + // The modulus is too big to encrypt. + string message(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len); + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, FinishOperation(&result)); + + // One smaller than the modulus is okay. + BN_sub(rsa->n, rsa->n, BN_value_one()); + modulus_len = BN_num_bytes(rsa->n); + ASSERT_EQ(256U / 8, modulus_len); + BN_bn2bin(rsa->n, modulus_buf.get()); + message = string(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&result)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} +#endif +#if RSA_TEST +TEST_P(EncryptionOperationsTest, RsaOaepSuccess) { + size_t key_size = 768; + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaEncryptionKey(key_size, 3) + .Padding(KM_PAD_RSA_OAEP) + .Digest(KM_DIGEST_SHA_2_256))); + + string message = "Hello"; + string ciphertext1 = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP); + EXPECT_EQ(key_size / 8, ciphertext1.size()); + + string ciphertext2 = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP); + EXPECT_EQ(key_size / 8, ciphertext2.size()); + + // OAEP randomizes padding so every result should be different. + EXPECT_NE(ciphertext1, ciphertext2); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} +#endif +#if RSA_TEST +TEST_P(EncryptionOperationsTest, RsaOaepSha224Success) { + size_t key_size = 768; + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaEncryptionKey(key_size, 3) + .Padding(KM_PAD_RSA_OAEP) + .Digest(KM_DIGEST_SHA_2_224))); + + string message = "Hello"; + string ciphertext1 = EncryptMessage(string(message), KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP); + EXPECT_EQ(key_size / 8, ciphertext1.size()); + + string ciphertext2 = EncryptMessage(string(message), KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP); + EXPECT_EQ(key_size / 8, ciphertext2.size()); + + // OAEP randomizes padding so every result should be different. + EXPECT_NE(ciphertext1, ciphertext2); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, RsaOaepRoundTrip) { + size_t key_size = 768; + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaEncryptionKey(key_size, 3) + .Padding(KM_PAD_RSA_OAEP) + .Digest(KM_DIGEST_SHA_2_256))); + string message = "Hello World!"; + string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP); + EXPECT_EQ(key_size / 8, ciphertext.size()); + + string plaintext = DecryptMessage(ciphertext, KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP); + EXPECT_EQ(message, plaintext); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, RsaOaepSha224RoundTrip) { + size_t key_size = 768; + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaEncryptionKey(key_size, 3) + .Padding(KM_PAD_RSA_OAEP) + .Digest(KM_DIGEST_SHA_2_224))); + string message = "Hello World!"; + string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP); + EXPECT_EQ(key_size / 8, ciphertext.size()); + + string plaintext = DecryptMessage(ciphertext, KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP); + EXPECT_EQ(message, plaintext); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, RsaOaepInvalidDigest) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaEncryptionKey(512, 3) + .Padding(KM_PAD_RSA_OAEP) + .Digest(KM_DIGEST_NONE))); + string message = "Hello World!"; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE); + EXPECT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, RsaOaepUnauthorizedDigest) { + if (GetParam()->minimal_digest_set()) + // We don't have two supported digests, so we can't try authorizing one and using another. + return; + + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaEncryptionKey(512, 3) + .Padding(KM_PAD_RSA_OAEP) + .Digest(KM_DIGEST_SHA_2_256))); + string message = "Hello World!"; + // Works because encryption is a public key operation. + EncryptMessage(string(message), KM_DIGEST_SHA1, KM_PAD_RSA_OAEP); + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA1); + EXPECT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) { + if (GetParam()->minimal_digest_set()) + // We don't have two supported digests, so we can't try encrypting with one and decrypting + // with another. + return; + + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaEncryptionKey(768, 3) + .Padding(KM_PAD_RSA_OAEP) + .Digest(KM_DIGEST_SHA_2_256) + .Digest(KM_DIGEST_SHA_2_384))); + string message = "Hello World!"; + string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP); + + string result; + size_t input_consumed; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_384); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &result, &input_consumed)); + EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(&result)); + EXPECT_EQ(0U, result.size()); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, RsaOaepTooLarge) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaEncryptionKey(512, 3) + .Padding(KM_PAD_RSA_OAEP) + .Digest(KM_DIGEST_SHA1))); + string message = "12345678901234567890123"; + string result; + size_t input_consumed; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA1); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&result)); + EXPECT_EQ(0U, result.size()); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, RsaOaepCorruptedDecrypt) { + size_t key_size = 768; + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaEncryptionKey(768, 3) + .Padding(KM_PAD_RSA_OAEP) + .Digest(KM_DIGEST_SHA_2_256))); + string message = "Hello World!"; + string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP); + EXPECT_EQ(key_size / 8, ciphertext.size()); + + // Corrupt the ciphertext + ciphertext[key_size / 8 / 2]++; + + string result; + size_t input_consumed; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &result, &input_consumed)); + EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(&result)); + EXPECT_EQ(0U, result.size()); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} +#endif +#if RSA_TEST +TEST_P(EncryptionOperationsTest, RsaPkcs1Success) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding( + KM_PAD_RSA_PKCS1_1_5_ENCRYPT))); + string message = "Hello World!"; + string ciphertext1 = EncryptMessage(message, KM_PAD_RSA_PKCS1_1_5_ENCRYPT); + EXPECT_EQ(512U / 8, ciphertext1.size()); + + string ciphertext2 = EncryptMessage(message, KM_PAD_RSA_PKCS1_1_5_ENCRYPT); + EXPECT_EQ(512U / 8, ciphertext2.size()); + + // PKCS1 v1.5 randomizes padding so every result should be different. + EXPECT_NE(ciphertext1, ciphertext2); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, RsaPkcs1RoundTrip) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding( + KM_PAD_RSA_PKCS1_1_5_ENCRYPT))); + string message = "Hello World!"; + string ciphertext = EncryptMessage(message, KM_PAD_RSA_PKCS1_1_5_ENCRYPT); + EXPECT_EQ(512U / 8, ciphertext.size()); + + string plaintext = DecryptMessage(ciphertext, KM_PAD_RSA_PKCS1_1_5_ENCRYPT); + EXPECT_EQ(message, plaintext); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} +#endif +#if CHECK_FAIL +TEST_P(EncryptionOperationsTest, RsaRoundTripAllCombinations) { + size_t key_size = 2048; + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaEncryptionKey(key_size, 3) + .Padding(KM_PAD_RSA_PKCS1_1_5_ENCRYPT) + .Padding(KM_PAD_RSA_OAEP) + .Digest(KM_DIGEST_NONE) + .Digest(KM_DIGEST_MD5) + .Digest(KM_DIGEST_SHA1) + .Digest(KM_DIGEST_SHA_2_224) + .Digest(KM_DIGEST_SHA_2_256) + .Digest(KM_DIGEST_SHA_2_384) + .Digest(KM_DIGEST_SHA_2_512))); + + string message = "Hello World!"; + + keymaster_padding_t padding_modes[] = {KM_PAD_RSA_OAEP, KM_PAD_RSA_PKCS1_1_5_ENCRYPT}; + keymaster_digest_t digests[] = { + KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224, + KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512, + }; + + for (auto padding : padding_modes) + for (auto digest : digests) { + if (padding == KM_PAD_RSA_OAEP && digest == KM_DIGEST_NONE) + // OAEP requires a digest. + continue; + + string ciphertext = EncryptMessage(message, digest, padding); + EXPECT_EQ(key_size / 8, ciphertext.size()); + + string plaintext = DecryptMessage(ciphertext, digest, padding); + EXPECT_EQ(message, plaintext); + } + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(40, GetParam()->keymaster0_calls()); +} +#endif +#if RSA_TEST +TEST_P(EncryptionOperationsTest, RsaPkcs1TooLarge) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding( + KM_PAD_RSA_PKCS1_1_5_ENCRYPT))); + string message = "123456789012345678901234567890123456789012345678901234"; + string result; + size_t input_consumed; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&result)); + EXPECT_EQ(0U, result.size()); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, RsaPkcs1CorruptedDecrypt) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding( + KM_PAD_RSA_PKCS1_1_5_ENCRYPT))); + string message = "Hello World!"; + string ciphertext = EncryptMessage(string(message), KM_PAD_RSA_PKCS1_1_5_ENCRYPT); + EXPECT_EQ(512U / 8, ciphertext.size()); + + // Corrupt the ciphertext + ciphertext[512 / 8 / 2]++; + + string result; + size_t input_consumed; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &result, &input_consumed)); + EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(&result)); + EXPECT_EQ(0U, result.size()); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(4, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, RsaEncryptWithSigningKey) { + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().RsaSigningKey(256, 3).Padding(KM_PAD_NONE))); + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + ASSERT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(2, GetParam()->keymaster0_calls()); +} +#endif +#if EC_TEST +TEST_P(EncryptionOperationsTest, EcdsaEncrypt) { + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE))); + ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_ENCRYPT)); + ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_DECRYPT)); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(3, GetParam()->keymaster0_calls()); +} +#endif +#if HMAC_TEST +TEST_P(EncryptionOperationsTest, HmacEncrypt) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(KM_DIGEST_SHA_2_256) + .Padding(KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_ENCRYPT)); + ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_DECRYPT)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +#if AES_TEST +TEST_P(EncryptionOperationsTest, AesEcbRoundTripSuccess) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB) + .Padding(KM_PAD_NONE))); + // Two-block message. + string message = "12345678901234567890123456789012"; + string ciphertext1 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE); + EXPECT_EQ(message.size(), ciphertext1.size()); + + string ciphertext2 = EncryptMessage(string(message), KM_MODE_ECB, KM_PAD_NONE); + EXPECT_EQ(message.size(), ciphertext2.size()); + + // ECB is deterministic. + EXPECT_EQ(ciphertext1, ciphertext2); + + string plaintext = DecryptMessage(ciphertext1, KM_MODE_ECB, KM_PAD_NONE); + EXPECT_EQ(message, plaintext); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesEcbNotAuthorized) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Padding(KM_PAD_NONE))); + // Two-block message. + string message = "12345678901234567890123456789012"; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + EXPECT_EQ(KM_ERROR_INCOMPATIBLE_BLOCK_MODE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB) + .Padding(KM_PAD_NONE))); + // Message is slightly shorter than two blocks. + string message = "1234567890123456789012345678901"; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + string ciphertext; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &ciphertext, &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&ciphertext)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +#if AES_TEST +TEST_P(EncryptionOperationsTest, AesEcbPkcs7Padding) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB) + .Authorization(TAG_PADDING, KM_PAD_PKCS7))); + + // Try various message lengths; all should work. + for (size_t i = 0; i < 32; ++i) { + string message(i, 'a'); + string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_PKCS7); + EXPECT_EQ(i + 16 - (i % 16), ciphertext.size()); + string plaintext = DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_PKCS7); + EXPECT_EQ(message, plaintext); + } + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +#if AES_TEST +TEST_P(EncryptionOperationsTest, AesEcbNoPaddingKeyWithPkcs7Padding) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB) + .Authorization(TAG_PADDING, KM_PAD_NONE))); + + // Try various message lengths; all should fail. + for (size_t i = 0; i < 32; ++i) { + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB); + begin_params.push_back(TAG_PADDING, KM_PAD_PKCS7); + EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE, + BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + } + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif + +#if AES_TEST +TEST_P(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB) + .Authorization(TAG_PADDING, KM_PAD_PKCS7))); + + string message = "a"; + string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_PKCS7); + EXPECT_EQ(16U, ciphertext.size()); + EXPECT_NE(ciphertext, message); + ++ciphertext[ciphertext.size() / 2]; + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB); + begin_params.push_back(TAG_PADDING, KM_PAD_PKCS7); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + string plaintext; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &plaintext, &input_consumed)); + EXPECT_EQ(ciphertext.size(), input_consumed); + EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, FinishOperation(&plaintext)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif + +#if AES_TEST +TEST_P(EncryptionOperationsTest, AesCtrRoundTripSuccess) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR) + .Padding(KM_PAD_NONE))); + string message = "123"; + string iv1; + string ciphertext1 = EncryptMessage(message, KM_MODE_CTR, KM_PAD_NONE, &iv1); + EXPECT_EQ(message.size(), ciphertext1.size()); + EXPECT_EQ(16U, iv1.size()); + + string iv2; + string ciphertext2 = EncryptMessage(message, KM_MODE_CTR, KM_PAD_NONE, &iv2); + EXPECT_EQ(message.size(), ciphertext2.size()); + EXPECT_EQ(16U, iv2.size()); + + // IVs should be random, so ciphertexts should differ. + EXPECT_NE(iv1, iv2); + EXPECT_NE(ciphertext1, ciphertext2); + + string plaintext = DecryptMessage(ciphertext1, KM_MODE_CTR, KM_PAD_NONE, iv1); + EXPECT_EQ(message, plaintext); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesCtrIncremental) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR) + .Padding(KM_PAD_NONE))); + + int increment = 15; + string message(239, 'a'); + AuthorizationSet input_params(client_params()); + input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR); + input_params.push_back(TAG_PADDING, KM_PAD_NONE); + AuthorizationSet output_params; + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, input_params, &output_params)); + + string ciphertext; + size_t input_consumed; + for (size_t i = 0; i < message.size(); i += increment) + EXPECT_EQ(KM_ERROR_OK, + UpdateOperation(message.substr(i, increment), &ciphertext, &input_consumed)); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext)); + EXPECT_EQ(message.size(), ciphertext.size()); + + // Move TAG_NONCE into input_params + input_params.Reinitialize(output_params); + input_params.push_back(client_params()); + input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR); + input_params.push_back(TAG_PADDING, KM_PAD_NONE); + output_params.Clear(); + + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, input_params, &output_params)); + string plaintext; + for (size_t i = 0; i < ciphertext.size(); i += increment) + EXPECT_EQ(KM_ERROR_OK, + UpdateOperation(ciphertext.substr(i, increment), &plaintext, &input_consumed)); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext)); + EXPECT_EQ(ciphertext.size(), plaintext.size()); + EXPECT_EQ(message, plaintext); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +struct AesCtrSp80038aTestVector { + const char* key; + const char* nonce; + const char* plaintext; + const char* ciphertext; +}; + +// These test vectors are taken from +// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section F.5. +static const AesCtrSp80038aTestVector kAesCtrSp80038aTestVectors[] = { + // AES-128 + { + "2b7e151628aed2a6abf7158809cf4f3c", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710", + "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff" + "5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee", + }, + // AES-192 + { + "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710", + "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e94" + "1e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050", + }, + // AES-256 + { + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710", + "601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c5" + "2b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6", + }, +}; + +TEST_P(EncryptionOperationsTest, AesCtrSp80038aTestVector) { + for (size_t i = 0; i < 3; i++) { + const AesCtrSp80038aTestVector& test(kAesCtrSp80038aTestVectors[i]); + const string key = hex2str(test.key); + const string nonce = hex2str(test.nonce); + const string plaintext = hex2str(test.plaintext); + const string ciphertext = hex2str(test.ciphertext); + CheckAesCtrTestVector(key, nonce, plaintext, ciphertext); + } + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesCtrInvalidPaddingMode) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR) + .Authorization(TAG_PADDING, KM_PAD_PKCS7))); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesCtrInvalidCallerNonce) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR) + .Authorization(TAG_CALLER_NONCE) + .Padding(KM_PAD_NONE))); + + AuthorizationSet input_params(client_params()); + input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR); + input_params.push_back(TAG_PADDING, KM_PAD_NONE); + input_params.push_back(TAG_NONCE, "123", 3); + EXPECT_EQ(KM_ERROR_INVALID_NONCE, BeginOperation(KM_PURPOSE_ENCRYPT, input_params)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesCbcRoundTripSuccess) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Padding(KM_PAD_NONE))); + // Two-block message. + string message = "12345678901234567890123456789012"; + string iv1; + string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1); + EXPECT_EQ(message.size(), ciphertext1.size()); + + string iv2; + string ciphertext2 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv2); + EXPECT_EQ(message.size(), ciphertext2.size()); + + // IVs should be random, so ciphertexts should differ. + EXPECT_NE(iv1, iv2); + EXPECT_NE(ciphertext1, ciphertext2); + + string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1); + EXPECT_EQ(message, plaintext); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesCallerNonce) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Authorization(TAG_CALLER_NONCE) + .Padding(KM_PAD_NONE))); + string message = "12345678901234567890123456789012"; + string iv1; + // Don't specify nonce, should get a random one. + string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1); + EXPECT_EQ(message.size(), ciphertext1.size()); + EXPECT_EQ(16U, iv1.size()); + + string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1); + EXPECT_EQ(message, plaintext); + + // Now specify a nonce, should also work. + AuthorizationSet input_params(client_params()); + AuthorizationSet update_params; + AuthorizationSet output_params; + input_params.push_back(TAG_NONCE, "abcdefghijklmnop", 16); + input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC); + input_params.push_back(TAG_PADDING, KM_PAD_NONE); + string ciphertext2 = + ProcessMessage(KM_PURPOSE_ENCRYPT, message, input_params, update_params, &output_params); + + // Decrypt with correct nonce. + plaintext = ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext2, input_params, update_params, + &output_params); + EXPECT_EQ(message, plaintext); + + // Now try with wrong nonce. + input_params.Reinitialize(client_params()); + input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC); + input_params.push_back(TAG_PADDING, KM_PAD_NONE); + input_params.push_back(TAG_NONCE, "aaaaaaaaaaaaaaaa", 16); + plaintext = ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext2, input_params, update_params, + &output_params); + EXPECT_NE(message, plaintext); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesCallerNonceProhibited) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Padding(KM_PAD_NONE))); + + string message = "12345678901234567890123456789012"; + string iv1; + // Don't specify nonce, should get a random one. + string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1); + EXPECT_EQ(message.size(), ciphertext1.size()); + EXPECT_EQ(16U, iv1.size()); + + string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1); + EXPECT_EQ(message, plaintext); + + // Now specify a nonce, should fail. + AuthorizationSet input_params(client_params()); + AuthorizationSet update_params; + AuthorizationSet output_params; + input_params.push_back(TAG_NONCE, "abcdefghijklmnop", 16); + input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC); + input_params.push_back(TAG_PADDING, KM_PAD_NONE); + + EXPECT_EQ(KM_ERROR_CALLER_NONCE_PROHIBITED, + BeginOperation(KM_PURPOSE_ENCRYPT, input_params, &output_params)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesCbcIncrementalNoPadding) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Padding(KM_PAD_NONE))); + + int increment = 15; + string message(240, 'a'); + AuthorizationSet input_params(client_params()); + input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC); + input_params.push_back(TAG_PADDING, KM_PAD_NONE); + AuthorizationSet output_params; + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, input_params, &output_params)); + + string ciphertext; + size_t input_consumed; + for (size_t i = 0; i < message.size(); i += increment) + EXPECT_EQ(KM_ERROR_OK, + UpdateOperation(message.substr(i, increment), &ciphertext, &input_consumed)); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext)); + EXPECT_EQ(message.size(), ciphertext.size()); + + // Move TAG_NONCE into input_params + input_params.Reinitialize(output_params); + input_params.push_back(client_params()); + input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC); + input_params.push_back(TAG_PADDING, KM_PAD_NONE); + output_params.Clear(); + + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, input_params, &output_params)); + string plaintext; + for (size_t i = 0; i < ciphertext.size(); i += increment) + EXPECT_EQ(KM_ERROR_OK, + UpdateOperation(ciphertext.substr(i, increment), &plaintext, &input_consumed)); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext)); + EXPECT_EQ(ciphertext.size(), plaintext.size()); + EXPECT_EQ(message, plaintext); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif + +#if AES_TEST +TEST_P(EncryptionOperationsTest, AesCbcPkcs7Padding) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC) + .Authorization(TAG_PADDING, KM_PAD_PKCS7))); + + // Try various message lengths; all should work. + for (size_t i = 0; i < 32; ++i) { + string message(i, 'a'); + string iv; + string ciphertext = EncryptMessage(message, KM_MODE_CBC, KM_PAD_PKCS7, &iv); + EXPECT_EQ(i + 16 - (i % 16), ciphertext.size()); + string plaintext = DecryptMessage(ciphertext, KM_MODE_CBC, KM_PAD_PKCS7, iv); + EXPECT_EQ(message, plaintext); + } + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +#if AES_TEST +TEST_P(EncryptionOperationsTest, AesGcmRoundTripSuccess) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + string aad = "foobar"; + string message = "123456789012345678901234567890123456"; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_MAC_LENGTH, 128); + + AuthorizationSet update_params; + update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size()); + + // Encrypt + AuthorizationSet begin_out_params; + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params)); + string ciphertext; + size_t input_consumed; + AuthorizationSet update_out_params; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext, + &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext)); + + // Grab nonce + EXPECT_NE(-1, begin_out_params.find(TAG_NONCE)); + begin_params.push_back(begin_out_params); + + // Decrypt. + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + string plaintext; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params, + &plaintext, &input_consumed)); + EXPECT_EQ(ciphertext.size(), input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext)); + + EXPECT_EQ(message, plaintext); + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesGcmTooShortTag) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + string aad = "foobar"; + string message = "123456789012345678901234567890123456"; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_MAC_LENGTH, 96); + + AuthorizationSet update_params; + update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size()); + + AuthorizationSet begin_out_params; + EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH, + BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + string aad = "foobar"; + string message = "123456789012345678901234567890123456"; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_MAC_LENGTH, 128); + + AuthorizationSet update_params; + update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size()); + + // Encrypt + AuthorizationSet begin_out_params; + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params)); + string ciphertext; + size_t input_consumed; + AuthorizationSet update_out_params; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext, + &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext)); + + // Grab nonce + EXPECT_NE(-1, begin_out_params.find(TAG_NONCE)); + begin_params.Reinitialize(client_params()); + begin_params.push_back(begin_out_params); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_MAC_LENGTH, 96); + + // Decrypt. + EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) { + uint8_t nonce[] = { + 0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f, + }; + uint8_t ciphertext[] = { + 0xb3, 0xf6, 0x79, 0x9e, 0x8f, 0x93, 0x26, 0xf2, 0xdf, 0x1e, 0x80, 0xfc, 0xd2, 0xcb, 0x16, + 0xd7, 0x8c, 0x9d, 0xc7, 0xcc, 0x14, 0xbb, 0x67, 0x78, 0x62, 0xdc, 0x6c, 0x63, 0x9b, 0x3a, + 0x63, 0x38, 0xd2, 0x4b, 0x31, 0x2d, 0x39, 0x89, 0xe5, 0x92, 0x0b, 0x5d, 0xbf, 0xc9, 0x76, + 0x76, 0x5e, 0xfb, 0xfe, 0x57, 0xbb, 0x38, 0x59, 0x40, 0xa7, 0xa4, 0x3b, 0xdf, 0x05, 0xbd, + 0xda, 0xe3, 0xc9, 0xd6, 0xa2, 0xfb, 0xbd, 0xfc, 0xc0, 0xcb, 0xa0, + }; + string ciphertext_str(reinterpret_cast<char*>(ciphertext), sizeof(ciphertext)); + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_MAC_LENGTH, 128); + begin_params.push_back(TAG_NONCE, nonce, sizeof(nonce)); + + string plaintext; + size_t input_consumed; + + // Import correct key and decrypt + uint8_t good_key[] = { + 0xba, 0x76, 0x35, 0x4f, 0x0a, 0xed, 0x6e, 0x8d, + 0x91, 0xf4, 0x5c, 0x4f, 0xf5, 0xa0, 0x62, 0xdb, + }; + string good_key_str(reinterpret_cast<char*>(good_key), sizeof(good_key)); + ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_CALLER_NONCE) + .Authorization(TAG_MIN_MAC_LENGTH, 128), + KM_KEY_FORMAT_RAW, good_key_str)); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext_str, &plaintext, &input_consumed)); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext)); + + // Import bad key and decrypt + uint8_t bad_key[] = { + 0xbb, 0x76, 0x35, 0x4f, 0x0a, 0xed, 0x6e, 0x8d, + 0x91, 0xf4, 0x5c, 0x4f, 0xf5, 0xa0, 0x62, 0xdb, + }; + string bad_key_str(reinterpret_cast<char*>(bad_key), sizeof(bad_key)); + ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128), + KM_KEY_FORMAT_RAW, bad_key_str)); + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext_str, &plaintext, &input_consumed)); + EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesGcmAadNoData) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + string aad = "123456789012345678"; + string empty_message; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_MAC_LENGTH, 128); + + AuthorizationSet update_params; + update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size()); + + // Encrypt + AuthorizationSet begin_out_params; + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params)); + string ciphertext; + size_t input_consumed; + AuthorizationSet update_out_params; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, empty_message, &update_out_params, + &ciphertext, &input_consumed)); + EXPECT_EQ(0U, input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext)); + + // Grab nonce + EXPECT_NE(-1, begin_out_params.find(TAG_NONCE)); + begin_params.push_back(begin_out_params); + + // Decrypt. + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + string plaintext; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params, + &plaintext, &input_consumed)); + EXPECT_EQ(ciphertext.size(), input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext)); + + EXPECT_EQ(empty_message, plaintext); + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +#if AES_TEST +TEST_P(EncryptionOperationsTest, AesGcmIncremental) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_MAC_LENGTH, 128); + + AuthorizationSet update_params; + update_params.push_back(TAG_ASSOCIATED_DATA, "b", 1); + + // Encrypt + AuthorizationSet begin_out_params; + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params)); + string ciphertext; + size_t input_consumed; + AuthorizationSet update_out_params; + + // Send AAD, incrementally + for (int i = 0; i < 1000; ++i) { + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, "", &update_out_params, &ciphertext, + &input_consumed)); + EXPECT_EQ(0U, input_consumed); + EXPECT_EQ(0U, ciphertext.size()); + } + + // Now send data, incrementally, no data. + AuthorizationSet empty_params; + for (int i = 0; i < 1000; ++i) { + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(empty_params, "a", &update_out_params, &ciphertext, + &input_consumed)); + EXPECT_EQ(1U, input_consumed); + } + EXPECT_EQ(1000U, ciphertext.size()); + + // And finish. + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext)); + EXPECT_EQ(1016U, ciphertext.size()); + + // Grab nonce + EXPECT_NE(-1, begin_out_params.find(TAG_NONCE)); + begin_params.push_back(begin_out_params); + + // Decrypt. + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + string plaintext; + + // Send AAD, incrementally, no data + for (int i = 0; i < 1000; ++i) { + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, "", &update_out_params, &plaintext, + &input_consumed)); + EXPECT_EQ(0U, input_consumed); + EXPECT_EQ(0U, plaintext.size()); + } + + // Now send data, incrementally. + for (size_t i = 0; i < ciphertext.length(); ++i) { + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(empty_params, string(ciphertext.data() + i, 1), + &update_out_params, &plaintext, &input_consumed)); + EXPECT_EQ(1U, input_consumed); + } + EXPECT_EQ(1000U, plaintext.size()); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesGcmMultiPartAad) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + string message = "123456789012345678901234567890123456"; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_MAC_LENGTH, 128); + AuthorizationSet begin_out_params; + + AuthorizationSet update_params; + update_params.push_back(TAG_ASSOCIATED_DATA, "foo", 3); + + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params)); + + // No data, AAD only. + string ciphertext; + size_t input_consumed; + AuthorizationSet update_out_params; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, "" /* message */, &update_out_params, + &ciphertext, &input_consumed)); + EXPECT_EQ(0U, input_consumed); + + // AAD and data. + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext, + &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext)); + + // Grab nonce. + EXPECT_NE(-1, begin_out_params.find(TAG_NONCE)); + begin_params.push_back(begin_out_params); + + // Decrypt + update_params.Clear(); + update_params.push_back(TAG_ASSOCIATED_DATA, "foofoo", 6); + + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params)); + string plaintext; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params, + &plaintext, &input_consumed)); + EXPECT_EQ(ciphertext.size(), input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext)); + + EXPECT_EQ(message, plaintext); + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesGcmBadAad) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + string message = "12345678901234567890123456789012"; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_MAC_LENGTH, 128); + + AuthorizationSet update_params; + update_params.push_back(TAG_ASSOCIATED_DATA, "foobar", 6); + + AuthorizationSet finish_params; + AuthorizationSet finish_out_params; + + // Encrypt + AuthorizationSet begin_out_params; + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params)); + AuthorizationSet update_out_params; + string ciphertext; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext, + &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext)); + + // Grab nonce + EXPECT_NE(-1, begin_out_params.find(TAG_NONCE)); + begin_params.push_back(begin_out_params); + + update_params.Clear(); + update_params.push_back(TAG_ASSOCIATED_DATA, "barfoo" /* Wrong AAD */, 6); + + // Decrypt. + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params, &begin_out_params)); + string plaintext; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params, + &plaintext, &input_consumed)); + EXPECT_EQ(ciphertext.size(), input_consumed); + EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(EncryptionOperationsTest, AesGcmWrongNonce) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + string message = "12345678901234567890123456789012"; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_MAC_LENGTH, 128); + + AuthorizationSet update_params; + update_params.push_back(TAG_ASSOCIATED_DATA, "foobar", 6); + + // Encrypt + AuthorizationSet begin_out_params; + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params)); + AuthorizationSet update_out_params; + string ciphertext; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext, + &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext)); + + begin_params.push_back(TAG_NONCE, "123456789012", 12); + + // Decrypt + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params, &begin_out_params)); + string plaintext; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params, + &plaintext, &input_consumed)); + EXPECT_EQ(ciphertext.size(), input_consumed); + EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext)); + + // With wrong nonce, should have gotten garbage plaintext. + EXPECT_NE(message, plaintext); + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +#if AES_TEST +TEST_P(EncryptionOperationsTest, AesGcmCorruptTag) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + string aad = "foobar"; + string message = "123456789012345678901234567890123456"; + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + begin_params.push_back(TAG_MAC_LENGTH, 128); + AuthorizationSet begin_out_params; + + AuthorizationSet update_params; + update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size()); + + // Encrypt + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params)); + AuthorizationSet update_out_params; + string ciphertext; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext, + &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext)); + + // Corrupt tag + (*ciphertext.rbegin())++; + + // Grab nonce. + EXPECT_NE(-1, begin_out_params.find(TAG_NONCE)); + begin_params.push_back(begin_out_params); + + // Decrypt. + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params, &begin_out_params)); + string plaintext; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params, + &plaintext, &input_consumed)); + EXPECT_EQ(ciphertext.size(), input_consumed); + EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext)); + + EXPECT_EQ(message, plaintext); + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +typedef Keymaster2Test MaxOperationsTest; +INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, MaxOperationsTest, test_params); +#if MAX_TEST +TEST_P(MaxOperationsTest, TestLimit) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .EcbMode() + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MAX_USES_PER_BOOT, 3))); + + string message = "1234567890123456"; + string ciphertext1 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE); + string ciphertext2 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE); + string ciphertext3 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE); + + // Fourth time should fail. + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + EXPECT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(MaxOperationsTest, TestAbort) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .EcbMode() + .Authorization(TAG_PADDING, KM_PAD_NONE) + .Authorization(TAG_MAX_USES_PER_BOOT, 3))); + + string message = "1234567890123456"; + string ciphertext1 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE); + string ciphertext2 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE); + string ciphertext3 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE); + + // Fourth time should fail. + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + EXPECT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +typedef Keymaster2Test AddEntropyTest; +INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, AddEntropyTest, test_params); +#if ENTROPY_TEST +TEST_P(AddEntropyTest, AddEntropy) { + // There's no obvious way to test that entropy is actually added, but we can test that the API + // doesn't blow up or return an error. + EXPECT_EQ(KM_ERROR_OK, + device()->add_rng_entropy(device(), reinterpret_cast<const uint8_t*>("foo"), 3)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +typedef Keymaster2Test Keymaster0AdapterTest; +#if 0 +INSTANTIATE_TEST_CASE_P( + AndroidKeymasterTest, Keymaster0AdapterTest, + ::testing::Values( + InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(true /* support_ec */)), + InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(false /* support_ec */)))); +#endif +TEST_P(Keymaster0AdapterTest, OldSoftwareKeymaster1RsaBlob) { + // Load and use an old-style Keymaster1 software key blob. These blobs contain OCB-encrypted + // key data. + string km1_sw = read_file("km1_sw_rsa_512.blob"); + EXPECT_EQ(486U, km1_sw.length()); + + uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km1_sw.length())); + memcpy(key_data, km1_sw.data(), km1_sw.length()); + set_key_blob(key_data, km1_sw.length()); + + string message(64, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(Keymaster0AdapterTest, UnversionedSoftwareKeymaster1RsaBlob) { + // Load and use an old-style Keymaster1 software key blob, without the version byte. These + // blobs contain OCB-encrypted key data. + string km1_sw = read_file("km1_sw_rsa_512_unversioned.blob"); + EXPECT_EQ(477U, km1_sw.length()); + + uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km1_sw.length())); + memcpy(key_data, km1_sw.data(), km1_sw.length()); + set_key_blob(key_data, km1_sw.length()); + + string message(64, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(Keymaster0AdapterTest, OldSoftwareKeymaster1EcdsaBlob) { + // Load and use an old-style Keymaster1 software key blob. These blobs contain OCB-encrypted + // key data. + string km1_sw = read_file("km1_sw_ecdsa_256.blob"); + EXPECT_EQ(270U, km1_sw.length()); + + uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km1_sw.length())); + memcpy(key_data, km1_sw.data(), km1_sw.length()); + set_key_blob(key_data, km1_sw.length()); + + string message(32, static_cast<char>(0xFF)); + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +struct Malloc_Delete { + void operator()(void* p) { free(p); } +}; + +TEST_P(Keymaster0AdapterTest, OldSoftwareKeymaster0RsaBlob) { + // Load and use an old softkeymaster blob. These blobs contain PKCS#8 key data. + string km0_sw = read_file("km0_sw_rsa_512.blob"); + EXPECT_EQ(333U, km0_sw.length()); + + uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length())); + memcpy(key_data, km0_sw.data(), km0_sw.length()); + set_key_blob(key_data, km0_sw.length()); + + string message(64, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(Keymaster0AdapterTest, OldSwKeymaster0RsaBlobGetCharacteristics) { + // Load and use an old softkeymaster blob. These blobs contain PKCS#8 key data. + string km0_sw = read_file("km0_sw_rsa_512.blob"); + EXPECT_EQ(333U, km0_sw.length()); + + uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length())); + memcpy(key_data, km0_sw.data(), km0_sw.length()); + set_key_blob(key_data, km0_sw.length()); + + EXPECT_EQ(KM_ERROR_OK, GetCharacteristics()); + EXPECT_TRUE(contains(sw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA)); + EXPECT_TRUE(contains(sw_enforced(), TAG_KEY_SIZE, 512)); + EXPECT_TRUE(contains(sw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 3)); + EXPECT_TRUE(contains(sw_enforced(), TAG_DIGEST, KM_DIGEST_NONE)); + EXPECT_TRUE(contains(sw_enforced(), TAG_PADDING, KM_PAD_NONE)); + EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_SIGN)); + EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_VERIFY)); + EXPECT_TRUE(sw_enforced().GetTagValue(TAG_ALL_USERS)); + EXPECT_TRUE(sw_enforced().GetTagValue(TAG_NO_AUTH_REQUIRED)); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(Keymaster0AdapterTest, OldHwKeymaster0RsaBlob) { + // Load and use an old softkeymaster blob. These blobs contain PKCS#8 key data. + string km0_sw = read_file("km0_sw_rsa_512.blob"); + EXPECT_EQ(333U, km0_sw.length()); + + // The keymaster0 wrapper swaps the old softkeymaster leading 'P' for a 'Q' to make the key not + // be recognized as a software key. Do the same here to pretend this is a hardware key. + EXPECT_EQ('P', km0_sw[0]); + km0_sw[0] = 'Q'; + + uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length())); + memcpy(key_data, km0_sw.data(), km0_sw.length()); + set_key_blob(key_data, km0_sw.length()); + + string message(64, 'a'); + string signature; + SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE); + VerifyMessage(message, signature, KM_DIGEST_NONE, KM_PAD_NONE); + + EXPECT_EQ(5, GetParam()->keymaster0_calls()); +} + +TEST_P(Keymaster0AdapterTest, OldHwKeymaster0RsaBlobGetCharacteristics) { + // Load and use an old softkeymaster blob. These blobs contain PKCS#8 key data. + string km0_sw = read_file("km0_sw_rsa_512.blob"); + EXPECT_EQ(333U, km0_sw.length()); + + // The keymaster0 wrapper swaps the old softkeymaster leading 'P' for a 'Q' to make the key not + // be recognized as a software key. Do the same here to pretend this is a hardware key. + EXPECT_EQ('P', km0_sw[0]); + km0_sw[0] = 'Q'; + + uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length())); + memcpy(key_data, km0_sw.data(), km0_sw.length()); + set_key_blob(key_data, km0_sw.length()); + + EXPECT_EQ(KM_ERROR_OK, GetCharacteristics()); + EXPECT_TRUE(contains(hw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA)); + EXPECT_TRUE(contains(hw_enforced(), TAG_KEY_SIZE, 512)); + EXPECT_TRUE(contains(hw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 3)); + EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_NONE)); + EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_MD5)); + EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA1)); + EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_224)); + EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_256)); + EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_384)); + EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_512)); + EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_NONE)); + EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT)); + EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN)); + EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_OAEP)); + EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_PSS)); + EXPECT_EQ(15U, hw_enforced().size()); + + EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_SIGN)); + EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_VERIFY)); + EXPECT_TRUE(sw_enforced().GetTagValue(TAG_ALL_USERS)); + EXPECT_TRUE(sw_enforced().GetTagValue(TAG_NO_AUTH_REQUIRED)); + + EXPECT_FALSE(contains(sw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA)); + EXPECT_FALSE(contains(sw_enforced(), TAG_KEY_SIZE, 512)); + EXPECT_FALSE(contains(sw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 3)); + EXPECT_FALSE(contains(sw_enforced(), TAG_DIGEST, KM_DIGEST_NONE)); + EXPECT_FALSE(contains(sw_enforced(), TAG_PADDING, KM_PAD_NONE)); + + EXPECT_EQ(1, GetParam()->keymaster0_calls()); +} + +typedef Keymaster2Test AttestationTest; +INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, AttestationTest, test_params); + +#if ATTESTATIONTEST +static X509* parse_cert_blob(const keymaster_blob_t& blob) { + const uint8_t* p = blob.data; + return d2i_X509(nullptr, &p, blob.data_length); +} + +static bool verify_chain(const keymaster_cert_chain_t& chain) { + for (size_t i = 0; i < chain.entry_count - 1; ++i) { + keymaster_blob_t& key_cert_blob = chain.entries[i]; + keymaster_blob_t& signing_cert_blob = chain.entries[i + 1]; + + X509_Ptr key_cert(parse_cert_blob(key_cert_blob)); + X509_Ptr signing_cert(parse_cert_blob(signing_cert_blob)); + EXPECT_TRUE(!!key_cert.get() && !!signing_cert.get()); + if (!key_cert.get() || !signing_cert.get()) + return false; + + EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get())); + EXPECT_TRUE(!!signing_pubkey.get()); + if (!signing_pubkey.get()) + return false; + + EXPECT_EQ(1, X509_verify(key_cert.get(), signing_pubkey.get())) + << "Verification of certificate " << i << " failed"; + } + + return true; +} + +// Extract attestation record from cert. Returned object is still part of cert; don't free it +// separately. +static ASN1_OCTET_STRING* get_attestation_record(X509* certificate) { + ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */)); + EXPECT_TRUE(!!oid.get()); + if (!oid.get()) + return nullptr; + + int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */); + EXPECT_NE(-1, location); + if (location == -1) + return nullptr; + + X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location); + EXPECT_TRUE(!!attest_rec_ext); + if (!attest_rec_ext) + return nullptr; + + ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext); + EXPECT_TRUE(!!attest_rec); + return attest_rec; +} + +static bool verify_attestation_record(const string& challenge, + AuthorizationSet expected_sw_enforced, + AuthorizationSet expected_tee_enforced, + uint32_t expected_keymaster_version, + keymaster_security_level_t expected_keymaster_security_level, + const keymaster_blob_t& attestation_cert) { + + X509_Ptr cert(parse_cert_blob(attestation_cert)); + EXPECT_TRUE(!!cert.get()); + if (!cert.get()) + return false; + + ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get()); + EXPECT_TRUE(!!attest_rec); + if (!attest_rec) + return false; + + AuthorizationSet att_sw_enforced; + AuthorizationSet att_tee_enforced; + uint32_t att_attestation_version; + uint32_t att_keymaster_version; + keymaster_security_level_t att_attestation_security_level; + keymaster_security_level_t att_keymaster_security_level; + keymaster_blob_t att_challenge = {}; + keymaster_blob_t att_unique_id = {}; + + EXPECT_EQ(KM_ERROR_OK, parse_attestation_record( + attest_rec->data, attest_rec->length, &att_attestation_version, + &att_attestation_security_level, &att_keymaster_version, + &att_keymaster_security_level, &att_challenge, &att_sw_enforced, + &att_tee_enforced, &att_unique_id)); + + EXPECT_EQ(1U, att_attestation_version); + EXPECT_EQ(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, att_attestation_security_level); + EXPECT_EQ(expected_keymaster_version, att_keymaster_version); + EXPECT_EQ(expected_keymaster_security_level, att_keymaster_security_level); + + EXPECT_EQ(challenge.length(), att_challenge.data_length); + EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data, challenge.length())); + + // Add TAG_USER_ID to the relevant attestation list, because user IDs are not included in + // attestations, since they're meaningless off-device. + uint32_t user_id; + if (expected_sw_enforced.GetTagValue(TAG_USER_ID, &user_id)) + att_sw_enforced.push_back(TAG_USER_ID, user_id); + if (expected_tee_enforced.GetTagValue(TAG_USER_ID, &user_id)) + att_tee_enforced.push_back(TAG_USER_ID, user_id); + + // Add TAG_INCLUDE_UNIQUE_ID to the relevant attestation list, because that tag is not included + // in the attestation. + if (expected_sw_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID)) + att_sw_enforced.push_back(TAG_INCLUDE_UNIQUE_ID); + if (expected_tee_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID)) + att_tee_enforced.push_back(TAG_INCLUDE_UNIQUE_ID); + + att_sw_enforced.Sort(); + expected_sw_enforced.Sort(); + EXPECT_EQ(expected_sw_enforced, att_sw_enforced); + + att_tee_enforced.Sort(); + expected_tee_enforced.Sort(); + EXPECT_EQ(expected_tee_enforced, att_tee_enforced); + + return true; +} +#endif +#if ATTESTATIONTEST +TEST_P(AttestationTest, RsaAttestation) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(256, 3) + .Digest(KM_DIGEST_NONE) + .Padding(KM_PAD_NONE) + .Authorization(TAG_INCLUDE_UNIQUE_ID))); + + keymaster_cert_chain_t cert_chain; + EXPECT_EQ(KM_ERROR_OK, AttestKey("challenge", &cert_chain)); + EXPECT_EQ(3U, cert_chain.entry_count); + EXPECT_TRUE(verify_chain(cert_chain)); + + uint32_t expected_keymaster_version; + keymaster_security_level_t expected_keymaster_security_level; + expected_keymaster_version = 2; + expected_keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT; + + EXPECT_TRUE(verify_attestation_record( + "challenge", sw_enforced(), hw_enforced(), expected_keymaster_version, + expected_keymaster_security_level, cert_chain.entries[0])); + + keymaster_free_cert_chain(&cert_chain); +} +#endif +#if ATTESTATIONTEST +TEST_P(AttestationTest, EcAttestation) { + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest( + KM_DIGEST_SHA_2_256))); + + uint32_t expected_keymaster_version; + keymaster_security_level_t expected_keymaster_security_level; + expected_keymaster_version = 2; + expected_keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT; + + keymaster_cert_chain_t cert_chain; + EXPECT_EQ(KM_ERROR_OK, AttestKey("challenge", &cert_chain)); + EXPECT_EQ(3U, cert_chain.entry_count); + EXPECT_TRUE(verify_chain(cert_chain)); + EXPECT_TRUE(verify_attestation_record( + "challenge", sw_enforced(), hw_enforced(), expected_keymaster_version, + expected_keymaster_security_level, cert_chain.entries[0])); + + keymaster_free_cert_chain(&cert_chain); +} +#endif +typedef Keymaster2Test KeyUpgradeTest; +INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, KeyUpgradeTest, test_params); +#if KEYUPGRADETEST +TEST_P(KeyUpgradeTest, AesVersionUpgrade) { + // A workaround for testing TEE based keymaster 2 from normal world + keymaster2_device_t* device = (keymaster2_device_t* )GetParam()->keymaster_context(); + AuthorizationSet version_info(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, 1) + .Authorization(TAG_OS_PATCHLEVEL, 1)); + device->configure(device, &version_info); + + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB) + .Padding(KM_PAD_NONE))); + + // Key should operate fine. + string message = "1234567890123456"; + string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE); + EXPECT_EQ(message, DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_NONE)); + + // Increase patch level. Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE. + AuthorizationSet version_info_1_2(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, 1) + .Authorization(TAG_OS_PATCHLEVEL, 2)); + device->configure(device, &version_info_1_2); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + if (GetParam()->is_keymaster1_hw()) { + // Keymaster1 hardware can't support version binding. The key will work regardless + // of system version. Just abort the remainder of the test. + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_OK, AbortOperation()); + return; + } + EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + + // Getting characteristics should also fail + EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics()); + + // Upgrade key. + EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params())); + + // Key should work again + ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE); + EXPECT_EQ(message, DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_NONE)); + + // Decrease patch level. Key usage should fail with KM_ERROR_INVALID_KEY_BLOB. + AuthorizationSet version_info_1_1(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, 1) + .Authorization(TAG_OS_PATCHLEVEL, 1)); + device->configure(device, &version_info_1_1); + + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics()); + + // Upgrade should fail + EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params())); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} +#endif +#if 0//KEYUPGRADETEST +//this test is no longer valid because boring ssl rejects rsa keys less than 256 bits +TEST_P(KeyUpgradeTest, RsaVersionUpgrade) { + keymaster2_device_t* device = (keymaster2_device_t* )GetParam()->keymaster_context(); + AuthorizationSet version_info(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, 1) + .Authorization(TAG_OS_PATCHLEVEL, 1)); + device->configure(device, &version_info); + + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(128, 3).Padding(KM_PAD_NONE))); + + // Key should operate fine. + string message = "1234567890123456"; + string ciphertext = EncryptMessage(message, KM_PAD_NONE); + EXPECT_EQ(message, DecryptMessage(ciphertext, KM_PAD_NONE)); + + // Increase patch level. Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE. + AuthorizationSet version_info_1_2(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, 1) + .Authorization(TAG_OS_PATCHLEVEL, 2)); + device->configure(device, &version_info_1_2); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + if (GetParam()->is_keymaster1_hw()) { + // Keymaster1 hardware can't support version binding. The key will work regardless + // of system version. Just abort the remainder of the test. + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_OK, AbortOperation()); + return; + } + EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + + // Getting characteristics should also fail + EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics()); + + // Upgrade key. + EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params())); + + // Key should work again + ciphertext = EncryptMessage(message, KM_PAD_NONE); + EXPECT_EQ(message, DecryptMessage(ciphertext, KM_PAD_NONE)); + + // Decrease patch level. Key usage should fail with KM_ERROR_INVALID_KEY_BLOB. + AuthorizationSet version_info_1_1(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, 1) + .Authorization(TAG_OS_PATCHLEVEL, 1)); + device->configure(device, &version_info_1_1); + + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics()); + + // Upgrade should fail + EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params())); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(7, GetParam()->keymaster0_calls()); +} +#endif +#if KEYUPGRADETEST +TEST_P(KeyUpgradeTest, EcVersionUpgrade) { + keymaster2_device_t* device = (keymaster2_device_t* )GetParam()->keymaster_context(); + AuthorizationSet version_info(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, 1) + .Authorization(TAG_OS_PATCHLEVEL, 1)); + device->configure(device, &version_info); + + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest( + KM_DIGEST_SHA_2_256))); + + // Key should operate fine. + string message = "1234567890123456"; + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_256); + VerifyMessage(message, signature, KM_DIGEST_SHA_2_256); + + // Increase patch level. Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE. + AuthorizationSet version_info_1_2(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, 1) + .Authorization(TAG_OS_PATCHLEVEL, 2)); + device->configure(device, &version_info_1_2); + + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256); + if (GetParam()->is_keymaster1_hw()) { + // Keymaster1 hardware can't support version binding. The key will work regardless + // of system version. Just abort the remainder of the test. + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params)); + EXPECT_EQ(KM_ERROR_OK, AbortOperation()); + return; + } + EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_SIGN, begin_params)); + + // Getting characteristics should also fail + EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics()); + + // Upgrade key. + EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params())); + + // Key should work again + SignMessage(message, &signature, KM_DIGEST_SHA_2_256); + VerifyMessage(message, signature, KM_DIGEST_SHA_2_256); + + // Decrease patch level. Key usage should fail with KM_ERROR_INVALID_KEY_BLOB. + AuthorizationSet version_info_1_1(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, 1) + .Authorization(TAG_OS_PATCHLEVEL, 1)); + device->configure(device, &version_info_1_1); + + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics()); + + // Upgrade should fail + EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params())); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(7, GetParam()->keymaster0_calls()); +} +#endif +#if 0 +TEST(SoftKeymasterWrapperTest, CheckKeymaster2Device) { + // Make a good fake device, and wrap it. + SoftKeymasterDevice* good_fake(new SoftKeymasterDevice(new TestKeymasterContext)); + + // Wrap it and check it. + SoftKeymasterDevice* good_fake_wrapper(new SoftKeymasterDevice(new TestKeymasterContext)); + good_fake_wrapper->SetHardwareDevice(good_fake->keymaster_device()); + EXPECT_TRUE(good_fake_wrapper->Keymaster1DeviceIsGood()); + + // Close and clean up wrapper and wrapped + good_fake_wrapper->keymaster_device()->common.close(good_fake_wrapper->hw_device()); + + // Make a "bad" (doesn't support all digests) device; + keymaster1_device_t* sha256_only_fake = make_device_sha256_only( + (new SoftKeymasterDevice(new TestKeymasterContext("256")))->keymaster_device()); + + // Wrap it and check it. + SoftKeymasterDevice* sha256_only_fake_wrapper( + (new SoftKeymasterDevice(new TestKeymasterContext))); + sha256_only_fake_wrapper->SetHardwareDevice(sha256_only_fake); + EXPECT_FALSE(sha256_only_fake_wrapper->Keymaster1DeviceIsGood()); + + // Close and clean up wrapper and wrapped + sha256_only_fake_wrapper->keymaster_device()->common.close( + sha256_only_fake_wrapper->hw_device()); +} +#endif + +} // namespace test +} // namespace keymaster diff --git a/unit_test/android_keymaster_test_utils.cpp b/unit_test/android_keymaster_test_utils.cpp new file mode 100644 index 0000000..ecaee62 --- a/dev/null +++ b/unit_test/android_keymaster_test_utils.cpp @@ -0,0 +1,902 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "android_keymaster_test_utils.h" + +#include <algorithm> + +#include <openssl/rand.h> + +#include <keymaster/android_keymaster_messages.h> +#include <keymaster/android_keymaster_utils.h> + +using std::copy_if; +using std::find_if; +using std::is_permutation; +using std::ostream; +using std::string; +using std::vector; + +#ifndef KEYMASTER_NAME_TAGS +#error Keymaster test code requires that KEYMASTER_NAME_TAGS is defined +#endif + +std::ostream& operator<<(std::ostream& os, const keymaster_key_param_t& param) { + os << "Tag: " << keymaster::StringifyTag(param.tag); + switch (keymaster_tag_get_type(param.tag)) { + case KM_INVALID: + os << " Invalid"; + break; + case KM_UINT_REP: + os << " (Rep)"; + /* Falls through */ + case KM_UINT: + os << " Int: " << param.integer; + break; + case KM_ENUM_REP: + os << " (Rep)"; + /* Falls through */ + case KM_ENUM: + os << " Enum: " << param.enumerated; + break; + case KM_ULONG_REP: + os << " (Rep)"; + /* Falls through */ + case KM_ULONG: + os << " Long: " << param.long_integer; + break; + case KM_DATE: + os << " Date: " << param.date_time; + break; + case KM_BOOL: + os << " Bool: " << param.boolean; + break; + case KM_BIGNUM: + os << " Bignum: "; + if (!param.blob.data) + os << "(null)"; + else + for (size_t i = 0; i < param.blob.data_length; ++i) + os << std::hex << std::setw(2) << static_cast<int>(param.blob.data[i]) << std::dec; + break; + case KM_BYTES: + os << " Bytes: "; + if (!param.blob.data) + os << "(null)"; + else + for (size_t i = 0; i < param.blob.data_length; ++i) + os << std::hex << std::setw(2) << static_cast<int>(param.blob.data[i]) << std::dec; + break; + } + return os; +} + +bool operator==(const keymaster_key_param_t& a, const keymaster_key_param_t& b) { + if (a.tag != b.tag) { + return false; + } + + switch (keymaster_tag_get_type(a.tag)) { + case KM_INVALID: + return true; + case KM_UINT_REP: + case KM_UINT: + return a.integer == b.integer; + case KM_ENUM_REP: + case KM_ENUM: + return a.enumerated == b.enumerated; + case KM_ULONG: + case KM_ULONG_REP: + return a.long_integer == b.long_integer; + case KM_DATE: + return a.date_time == b.date_time; + case KM_BOOL: + return a.boolean == b.boolean; + case KM_BIGNUM: + case KM_BYTES: + if ((a.blob.data == NULL || b.blob.data == NULL) && a.blob.data != b.blob.data) + return false; + return a.blob.data_length == b.blob.data_length && + (memcmp(a.blob.data, b.blob.data, a.blob.data_length) == 0); + } + + return false; +} + +static char hex_value[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9' + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, 0, + 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +string hex2str(string a) { + string b; + size_t num = a.size() / 2; + b.resize(num); + for (size_t i = 0; i < num; i++) { + b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]); + } + return b; +} + +namespace keymaster { + +bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) { + if (a.size() != b.size()) + return false; + + for (size_t i = 0; i < a.size(); ++i) + if (!(a[i] == b[i])) + return false; + return true; +} + +bool operator!=(const AuthorizationSet& a, const AuthorizationSet& b) { + return !(a == b); +} + +std::ostream& operator<<(std::ostream& os, const AuthorizationSet& set) { + if (set.size() == 0) + os << "(Empty)" << std::endl; + else { + os << "\n"; + for (size_t i = 0; i < set.size(); ++i) + os << set[i] << std::endl; + } + return os; +} + +namespace test { + +Keymaster2Test::Keymaster2Test() : op_handle_(OP_HANDLE_SENTINEL) { + memset(&characteristics_, 0, sizeof(characteristics_)); + blob_.key_material = nullptr; + RAND_seed("foobar", 6); + blob_.key_material = 0; + device_ = GetParam()->CreateDevice(); +} + +Keymaster2Test::~Keymaster2Test() { + FreeCharacteristics(); + FreeKeyBlob(); + device_->common.close(reinterpret_cast<hw_device_t*>(device_)); +} + +keymaster2_device_t* Keymaster2Test::device() { + return device_; +} + +keymaster_error_t Keymaster2Test::GenerateKey(const AuthorizationSetBuilder& builder) { + AuthorizationSet params(builder.build()); + params.push_back(UserAuthParams()); + params.push_back(ClientParams()); + + FreeKeyBlob(); + FreeCharacteristics(); + return device()->generate_key(device(), ¶ms, &blob_, &characteristics_); +} + +keymaster_error_t Keymaster2Test::DeleteKey() { + return device()->delete_key(device(), &blob_); +} + +keymaster_error_t Keymaster2Test::ImportKey(const AuthorizationSetBuilder& builder, + keymaster_key_format_t format, + const string& key_material) { + AuthorizationSet params(builder.build()); + params.push_back(UserAuthParams()); + params.push_back(ClientParams()); + + FreeKeyBlob(); + FreeCharacteristics(); + keymaster_blob_t key = {reinterpret_cast<const uint8_t*>(key_material.c_str()), + key_material.length()}; + return device()->import_key(device(), ¶ms, format, &key, &blob_, &characteristics_); +} + +AuthorizationSet Keymaster2Test::UserAuthParams() { + AuthorizationSet set; + set.push_back(TAG_USER_ID, 7); + set.push_back(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD); + set.push_back(TAG_AUTH_TIMEOUT, 300); + return set; +} + +AuthorizationSet Keymaster2Test::ClientParams() { + AuthorizationSet set; + set.push_back(TAG_APPLICATION_ID, "app_id", 6); + return set; +} + +keymaster_error_t Keymaster2Test::BeginOperation(keymaster_purpose_t purpose) { + AuthorizationSet in_params(client_params()); + keymaster_key_param_set_t out_params; + keymaster_error_t error = + device()->begin(device(), purpose, &blob_, &in_params, &out_params, &op_handle_); + EXPECT_EQ(0U, out_params.length); + EXPECT_TRUE(out_params.params == nullptr); + return error; +} + +keymaster_error_t Keymaster2Test::BeginOperation(keymaster_purpose_t purpose, + const AuthorizationSet& input_set, + AuthorizationSet* output_set) { + keymaster_key_param_set_t out_params; + keymaster_error_t error = + device()->begin(device(), purpose, &blob_, &input_set, &out_params, &op_handle_); + if (error == KM_ERROR_OK) { + if (output_set) { + output_set->Reinitialize(out_params); + } else { + EXPECT_EQ(0U, out_params.length); + EXPECT_TRUE(out_params.params == nullptr); + } + keymaster_free_param_set(&out_params); + } + return error; +} + +keymaster_error_t Keymaster2Test::UpdateOperation(const string& message, string* output, + size_t* input_consumed) { + EXPECT_NE(op_handle_, OP_HANDLE_SENTINEL); + keymaster_blob_t input = {reinterpret_cast<const uint8_t*>(message.c_str()), message.length()}; + keymaster_blob_t out_tmp; + keymaster_key_param_set_t out_params; + keymaster_error_t error = device()->update(device(), op_handle_, nullptr /* params */, &input, + input_consumed, &out_params, &out_tmp); + if (error == KM_ERROR_OK && out_tmp.data) + output->append(reinterpret_cast<const char*>(out_tmp.data), out_tmp.data_length); + free(const_cast<uint8_t*>(out_tmp.data)); + return error; +} + +keymaster_error_t Keymaster2Test::UpdateOperation(const AuthorizationSet& additional_params, + const string& message, + AuthorizationSet* output_params, string* output, + size_t* input_consumed) { + EXPECT_NE(op_handle_, OP_HANDLE_SENTINEL); + keymaster_blob_t input = {reinterpret_cast<const uint8_t*>(message.c_str()), message.length()}; + keymaster_blob_t out_tmp; + keymaster_key_param_set_t out_params; + keymaster_error_t error = device()->update(device(), op_handle_, &additional_params, &input, + input_consumed, &out_params, &out_tmp); + if (error == KM_ERROR_OK && out_tmp.data) + output->append(reinterpret_cast<const char*>(out_tmp.data), out_tmp.data_length); + free((void*)out_tmp.data); + if (output_params) + output_params->Reinitialize(out_params); + keymaster_free_param_set(&out_params); + return error; +} + +keymaster_error_t Keymaster2Test::FinishOperation(string* output) { + return FinishOperation("", output); +} + +keymaster_error_t Keymaster2Test::FinishOperation(const string& signature, string* output) { + AuthorizationSet additional_params; + AuthorizationSet output_params; + return FinishOperation(additional_params, signature, &output_params, output); +} + +keymaster_error_t Keymaster2Test::FinishOperation(const AuthorizationSet& additional_params, + const string& signature, + AuthorizationSet* output_params, string* output) { + keymaster_blob_t sig = {reinterpret_cast<const uint8_t*>(signature.c_str()), + signature.length()}; + keymaster_blob_t out_tmp; + keymaster_key_param_set_t out_params; + keymaster_error_t error = device()->finish(device(), op_handle_, &additional_params, + nullptr /* input */, &sig, &out_params, &out_tmp); + if (error != KM_ERROR_OK) { + EXPECT_TRUE(out_tmp.data == nullptr); + EXPECT_TRUE(out_params.params == nullptr); + return error; + } + + if (out_tmp.data) + output->append(reinterpret_cast<const char*>(out_tmp.data), out_tmp.data_length); + free((void*)out_tmp.data); + if (output_params) + output_params->Reinitialize(out_params); + keymaster_free_param_set(&out_params); + return error; +} + +keymaster_error_t Keymaster2Test::AbortOperation() { + return device()->abort(device(), op_handle_); +} + +keymaster_error_t Keymaster2Test::AttestKey(const string& attest_challenge, + keymaster_cert_chain_t* cert_chain) { + AuthorizationSet attest_params; + attest_params.push_back(UserAuthParams()); + attest_params.push_back(ClientParams()); + attest_params.push_back(TAG_ATTESTATION_CHALLENGE, attest_challenge.data(), + attest_challenge.length()); + return device()->attest_key(device(), &blob_, &attest_params, cert_chain); +} + +keymaster_error_t Keymaster2Test::UpgradeKey(const AuthorizationSet& upgrade_params) { + keymaster_key_blob_t upgraded_blob; + keymaster_error_t error = + device()->upgrade_key(device(), &blob_, &upgrade_params, &upgraded_blob); + if (error == KM_ERROR_OK) { + FreeKeyBlob(); + blob_ = upgraded_blob; + } + return error; +} + +string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message) { + EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, client_params(), NULL /* output_params */)); + + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(&result)); + return result; +} + +string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message, + const AuthorizationSet& begin_params, + const AuthorizationSet& update_params, + AuthorizationSet* begin_out_params) { + EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, begin_params, begin_out_params)); + + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, nullptr /* output_params */, + &result, &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(update_params, "", &result)); + return result; +} + +string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message, + const string& signature, const AuthorizationSet& begin_params, + const AuthorizationSet& update_params, + AuthorizationSet* output_params) { + EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, begin_params, output_params)); + + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, nullptr /* output_params */, + &result, &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(update_params, signature, &result)); + return result; +} + +string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message, + const string& signature) { + EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, client_params(), NULL /* output_params */)); + + string result; + size_t input_consumed; + EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_EQ(KM_ERROR_OK, FinishOperation(signature, &result)); + return result; +} + +void Keymaster2Test::SignMessage(const string& message, string* signature, + keymaster_digest_t digest) { + SCOPED_TRACE("SignMessage"); + AuthorizationSet input_params(AuthorizationSet(client_params_, array_length(client_params_))); + input_params.push_back(TAG_DIGEST, digest); + AuthorizationSet update_params; + AuthorizationSet output_params; + *signature = + ProcessMessage(KM_PURPOSE_SIGN, message, input_params, update_params, &output_params); + EXPECT_GT(signature->size(), 0U); +} + +void Keymaster2Test::SignMessage(const string& message, string* signature, + keymaster_digest_t digest, keymaster_padding_t padding) { + SCOPED_TRACE("SignMessage"); + AuthorizationSet input_params(AuthorizationSet(client_params_, array_length(client_params_))); + input_params.push_back(TAG_DIGEST, digest); + input_params.push_back(TAG_PADDING, padding); + AuthorizationSet update_params; + AuthorizationSet output_params; + *signature = + ProcessMessage(KM_PURPOSE_SIGN, message, input_params, update_params, &output_params); + EXPECT_GT(signature->size(), 0U); +} + +void Keymaster2Test::MacMessage(const string& message, string* signature, size_t mac_length) { + SCOPED_TRACE("SignMessage"); + AuthorizationSet input_params(AuthorizationSet(client_params_, array_length(client_params_))); + input_params.push_back(TAG_MAC_LENGTH, mac_length); + AuthorizationSet update_params; + AuthorizationSet output_params; + *signature = + ProcessMessage(KM_PURPOSE_SIGN, message, input_params, update_params, &output_params); + EXPECT_GT(signature->size(), 0U); +} + +void Keymaster2Test::VerifyMessage(const string& message, const string& signature, + keymaster_digest_t digest) { + SCOPED_TRACE("VerifyMessage"); + AuthorizationSet input_params(client_params()); + input_params.push_back(TAG_DIGEST, digest); + AuthorizationSet update_params; + AuthorizationSet output_params; + ProcessMessage(KM_PURPOSE_VERIFY, message, signature, input_params, update_params, + &output_params); +} + +void Keymaster2Test::VerifyMessage(const string& message, const string& signature, + keymaster_digest_t digest, keymaster_padding_t padding) { + SCOPED_TRACE("VerifyMessage"); + AuthorizationSet input_params(client_params()); + input_params.push_back(TAG_DIGEST, digest); + input_params.push_back(TAG_PADDING, padding); + AuthorizationSet update_params; + AuthorizationSet output_params; + ProcessMessage(KM_PURPOSE_VERIFY, message, signature, input_params, update_params, + &output_params); +} + +void Keymaster2Test::VerifyMac(const string& message, const string& signature) { + SCOPED_TRACE("VerifyMac"); + ProcessMessage(KM_PURPOSE_VERIFY, message, signature); +} + +string Keymaster2Test::EncryptMessage(const string& message, keymaster_padding_t padding, + string* generated_nonce) { + SCOPED_TRACE("EncryptMessage"); + AuthorizationSet begin_params(client_params()), output_params; + begin_params.push_back(TAG_PADDING, padding); + AuthorizationSet update_params; + string ciphertext = + ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params, &output_params); + if (generated_nonce) { + keymaster_blob_t nonce_blob; + EXPECT_TRUE(output_params.GetTagValue(TAG_NONCE, &nonce_blob)); + *generated_nonce = make_string(nonce_blob.data, nonce_blob.data_length); + } else { + EXPECT_EQ(-1, output_params.find(TAG_NONCE)); + } + return ciphertext; +} + +string Keymaster2Test::EncryptMessage(const string& message, keymaster_digest_t digest, + keymaster_padding_t padding, string* generated_nonce) { + AuthorizationSet update_params; + return EncryptMessage(update_params, message, digest, padding, generated_nonce); +} + +string Keymaster2Test::EncryptMessage(const string& message, keymaster_block_mode_t block_mode, + keymaster_padding_t padding, string* generated_nonce) { + AuthorizationSet update_params; + return EncryptMessage(update_params, message, block_mode, padding, generated_nonce); +} + +string Keymaster2Test::EncryptMessage(const AuthorizationSet& update_params, const string& message, + keymaster_digest_t digest, keymaster_padding_t padding, + string* generated_nonce) { + SCOPED_TRACE("EncryptMessage"); + AuthorizationSet begin_params(client_params()), output_params; + begin_params.push_back(TAG_PADDING, padding); + begin_params.push_back(TAG_DIGEST, digest); + string ciphertext = + ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params, &output_params); + if (generated_nonce) { + keymaster_blob_t nonce_blob; + EXPECT_TRUE(output_params.GetTagValue(TAG_NONCE, &nonce_blob)); + *generated_nonce = make_string(nonce_blob.data, nonce_blob.data_length); + } else { + EXPECT_EQ(-1, output_params.find(TAG_NONCE)); + } + return ciphertext; +} + +string Keymaster2Test::EncryptMessage(const AuthorizationSet& update_params, const string& message, + keymaster_block_mode_t block_mode, + keymaster_padding_t padding, string* generated_nonce) { + SCOPED_TRACE("EncryptMessage"); + AuthorizationSet begin_params(client_params()), output_params; + begin_params.push_back(TAG_PADDING, padding); + begin_params.push_back(TAG_BLOCK_MODE, block_mode); + string ciphertext = + ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params, &output_params); + if (generated_nonce) { + keymaster_blob_t nonce_blob; + EXPECT_TRUE(output_params.GetTagValue(TAG_NONCE, &nonce_blob)); + *generated_nonce = make_string(nonce_blob.data, nonce_blob.data_length); + } else { + EXPECT_EQ(-1, output_params.find(TAG_NONCE)); + } + return ciphertext; +} + +string Keymaster2Test::EncryptMessageWithParams(const string& message, + const AuthorizationSet& begin_params, + const AuthorizationSet& update_params, + AuthorizationSet* output_params) { + SCOPED_TRACE("EncryptMessageWithParams"); + return ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params, output_params); +} + +string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_padding_t padding) { + SCOPED_TRACE("DecryptMessage"); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, padding); + AuthorizationSet update_params; + return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params); +} + +string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_digest_t digest, + keymaster_padding_t padding) { + SCOPED_TRACE("DecryptMessage"); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, padding); + begin_params.push_back(TAG_DIGEST, digest); + AuthorizationSet update_params; + return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params); +} + +string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_block_mode_t block_mode, + keymaster_padding_t padding) { + SCOPED_TRACE("DecryptMessage"); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, padding); + begin_params.push_back(TAG_BLOCK_MODE, block_mode); + AuthorizationSet update_params; + return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params); +} + +string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_digest_t digest, + keymaster_padding_t padding, const string& nonce) { + SCOPED_TRACE("DecryptMessage"); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, padding); + begin_params.push_back(TAG_DIGEST, digest); + begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size()); + AuthorizationSet update_params; + return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params); +} + +string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_block_mode_t block_mode, + keymaster_padding_t padding, const string& nonce) { + SCOPED_TRACE("DecryptMessage"); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, padding); + begin_params.push_back(TAG_BLOCK_MODE, block_mode); + begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size()); + AuthorizationSet update_params; + return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params); +} + +string Keymaster2Test::DecryptMessage(const AuthorizationSet& update_params, + const string& ciphertext, keymaster_digest_t digest, + keymaster_padding_t padding, const string& nonce) { + SCOPED_TRACE("DecryptMessage"); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, padding); + begin_params.push_back(TAG_DIGEST, digest); + begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size()); + return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params); +} + +keymaster_error_t Keymaster2Test::GetCharacteristics() { + FreeCharacteristics(); + return device()->get_key_characteristics(device(), &blob_, &client_id_, NULL /* app_data */, + &characteristics_); +} + +keymaster_error_t Keymaster2Test::ExportKey(keymaster_key_format_t format, string* export_data) { + keymaster_blob_t export_tmp; + keymaster_error_t error = device()->export_key(device(), format, &blob_, &client_id_, + NULL /* app_data */, &export_tmp); + + if (error != KM_ERROR_OK) + return error; + + *export_data = string(reinterpret_cast<const char*>(export_tmp.data), export_tmp.data_length); + free((void*)export_tmp.data); + return error; +} + +void Keymaster2Test::CheckHmacTestVector(const string& key, const string& message, keymaster_digest_t digest, + string expected_mac) { + ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder() + .HmacKey(key.size() * 8) + .Authorization(TAG_MIN_MAC_LENGTH, expected_mac.size() * 8) + .Digest(digest), + KM_KEY_FORMAT_RAW, key)); + string signature; + MacMessage(message, &signature, expected_mac.size() * 8); + EXPECT_EQ(expected_mac, signature) << "Test vector didn't match for digest " << (int)digest; +} + +void Keymaster2Test::CheckAesCtrTestVector(const string& key, const string& nonce, + const string& message, + const string& expected_ciphertext) { + ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder() + .AesEncryptionKey(key.size() * 8) + .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR) + .Authorization(TAG_CALLER_NONCE) + .Padding(KM_PAD_NONE), + KM_KEY_FORMAT_RAW, key)); + + AuthorizationSet begin_params(client_params()), update_params, output_params; + begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + string ciphertext = + EncryptMessageWithParams(message, begin_params, update_params, &output_params); + EXPECT_EQ(expected_ciphertext, ciphertext); +} + +AuthorizationSet Keymaster2Test::hw_enforced() { + return AuthorizationSet(characteristics_.hw_enforced); +} + +AuthorizationSet Keymaster2Test::sw_enforced() { + return AuthorizationSet(characteristics_.sw_enforced); +} + +void Keymaster2Test::FreeCharacteristics() { + keymaster_free_characteristics(&characteristics_); +} + +void Keymaster2Test::FreeKeyBlob() { + free(const_cast<uint8_t*>(blob_.key_material)); + blob_.key_material = NULL; +} + +void Keymaster2Test::corrupt_key_blob() { + assert(blob_.key_material); + uint8_t* tmp = const_cast<uint8_t*>(blob_.key_material); + ++tmp[blob_.key_material_size / 2]; +} + +class Sha256OnlyWrapper { + public: + explicit Sha256OnlyWrapper(const keymaster1_device_t* wrapped_device) : wrapped_device_(wrapped_device) { + + new_module = *wrapped_device_->common.module; + new_module_name = std::string("SHA 256-only ") + wrapped_device_->common.module->name; + new_module.name = new_module_name.c_str(); + + memset(&device_, 0, sizeof(device_)); + device_.common.module = &new_module; + + device_.common.close = close_device; + device_.get_supported_algorithms = get_supported_algorithms; + device_.get_supported_block_modes = get_supported_block_modes; + device_.get_supported_padding_modes = get_supported_padding_modes; + device_.get_supported_digests = get_supported_digests; + device_.get_supported_import_formats = get_supported_import_formats; + device_.get_supported_export_formats = get_supported_export_formats; + device_.add_rng_entropy = add_rng_entropy; + device_.generate_key = generate_key; + device_.get_key_characteristics = get_key_characteristics; + device_.import_key = import_key; + device_.export_key = export_key; + device_.begin = begin; + device_.update = update; + device_.finish = finish; + device_.abort = abort; + } + + keymaster1_device_t* keymaster_device() { return &device_; } + + static bool is_supported(keymaster_digest_t digest) { + return digest == KM_DIGEST_NONE || digest == KM_DIGEST_SHA_2_256; + } + + static bool all_digests_supported(const keymaster_key_param_set_t* params) { + for (size_t i = 0; i < params->length; ++i) + if (params->params[i].tag == TAG_DIGEST) + if (!is_supported(static_cast<keymaster_digest_t>(params->params[i].enumerated))) + return false; + return true; + } + + static const keymaster_key_param_t* + get_algorithm_param(const keymaster_key_param_set_t* params) { + keymaster_key_param_t* end = params->params + params->length; + auto alg_ptr = std::find_if(params->params, end, [](keymaster_key_param_t& p) { + return p.tag == KM_TAG_ALGORITHM; + }); + if (alg_ptr == end) + return nullptr; + return alg_ptr; + } + + static int close_device(hw_device_t* dev) { + Sha256OnlyWrapper* wrapper = reinterpret_cast<Sha256OnlyWrapper*>(dev); + const keymaster1_device_t* wrapped_device = wrapper->wrapped_device_; + delete wrapper; + return wrapped_device->common.close(const_cast<hw_device_t*>(&wrapped_device->common)); + } + + static const keymaster1_device_t* unwrap(const keymaster1_device_t* dev) { + return reinterpret_cast<const Sha256OnlyWrapper*>(dev)->wrapped_device_; + } + + static keymaster_error_t get_supported_algorithms(const struct keymaster1_device* dev, + keymaster_algorithm_t** algorithms, + size_t* algorithms_length) { + return unwrap(dev)->get_supported_algorithms(unwrap(dev), algorithms, algorithms_length); + } + static keymaster_error_t get_supported_block_modes(const struct keymaster1_device* dev, + keymaster_algorithm_t algorithm, + keymaster_purpose_t purpose, + keymaster_block_mode_t** modes, + size_t* modes_length) { + return unwrap(dev)->get_supported_block_modes(unwrap(dev), algorithm, purpose, modes, + modes_length); + } + static keymaster_error_t get_supported_padding_modes(const struct keymaster1_device* dev, + keymaster_algorithm_t algorithm, + keymaster_purpose_t purpose, + keymaster_padding_t** modes, + size_t* modes_length) { + return unwrap(dev)->get_supported_padding_modes(unwrap(dev), algorithm, purpose, modes, + modes_length); + } + + static keymaster_error_t get_supported_digests(const keymaster1_device_t* dev, + keymaster_algorithm_t algorithm, + keymaster_purpose_t purpose, + keymaster_digest_t** digests, + size_t* digests_length) { + keymaster_error_t error = unwrap(dev)->get_supported_digests( + unwrap(dev), algorithm, purpose, digests, digests_length); + if (error != KM_ERROR_OK) + return error; + + std::vector<keymaster_digest_t> filtered_digests; + std::copy_if(*digests, *digests + *digests_length, std::back_inserter(filtered_digests), + [](keymaster_digest_t digest) { return is_supported(digest); }); + + free(*digests); + *digests_length = filtered_digests.size(); + *digests = reinterpret_cast<keymaster_digest_t*>( + malloc(*digests_length * sizeof(keymaster_digest_t))); + std::copy(filtered_digests.begin(), filtered_digests.end(), *digests); + + return KM_ERROR_OK; + } + + static keymaster_error_t get_supported_import_formats(const struct keymaster1_device* dev, + keymaster_algorithm_t algorithm, + keymaster_key_format_t** formats, + size_t* formats_length) { + return unwrap(dev)->get_supported_import_formats(unwrap(dev), algorithm, formats, + formats_length); + } + static keymaster_error_t get_supported_export_formats(const struct keymaster1_device* dev, + keymaster_algorithm_t algorithm, + keymaster_key_format_t** formats, + size_t* formats_length) { + return unwrap(dev)->get_supported_export_formats(unwrap(dev), algorithm, formats, + formats_length); + } + static keymaster_error_t add_rng_entropy(const struct keymaster1_device* dev, + const uint8_t* data, size_t data_length) { + return unwrap(dev)->add_rng_entropy(unwrap(dev), data, data_length); + } + + static keymaster_error_t generate_key(const keymaster1_device_t* dev, + const keymaster_key_param_set_t* params, + keymaster_key_blob_t* key_blob, + keymaster_key_characteristics_t** characteristics) { + auto alg_ptr = get_algorithm_param(params); + if (!alg_ptr) + return KM_ERROR_UNSUPPORTED_ALGORITHM; + if (alg_ptr->enumerated == KM_ALGORITHM_HMAC && !all_digests_supported(params)) + return KM_ERROR_UNSUPPORTED_DIGEST; + + return unwrap(dev)->generate_key(unwrap(dev), params, key_blob, characteristics); + } + + static keymaster_error_t + get_key_characteristics(const struct keymaster1_device* dev, + const keymaster_key_blob_t* key_blob, const keymaster_blob_t* client_id, + const keymaster_blob_t* app_data, + keymaster_key_characteristics_t** characteristics) { + return unwrap(dev)->get_key_characteristics(unwrap(dev), key_blob, client_id, app_data, + characteristics); + } + + static keymaster_error_t + import_key(const keymaster1_device_t* dev, const keymaster_key_param_set_t* params, + keymaster_key_format_t key_format, const keymaster_blob_t* key_data, + keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t** characteristics) { + auto alg_ptr = get_algorithm_param(params); + if (!alg_ptr) + return KM_ERROR_UNSUPPORTED_ALGORITHM; + if (alg_ptr->enumerated == KM_ALGORITHM_HMAC && !all_digests_supported(params)) + return KM_ERROR_UNSUPPORTED_DIGEST; + + return unwrap(dev)->import_key(unwrap(dev), params, key_format, key_data, key_blob, + characteristics); + } + + static keymaster_error_t export_key(const struct keymaster1_device* dev, // + keymaster_key_format_t export_format, + const keymaster_key_blob_t* key_to_export, + const keymaster_blob_t* client_id, + const keymaster_blob_t* app_data, + keymaster_blob_t* export_data) { + return unwrap(dev)->export_key(unwrap(dev), export_format, key_to_export, client_id, + app_data, export_data); + } + + static keymaster_error_t begin(const keymaster1_device_t* dev, // + keymaster_purpose_t purpose, const keymaster_key_blob_t* key, + const keymaster_key_param_set_t* in_params, + keymaster_key_param_set_t* out_params, + keymaster_operation_handle_t* operation_handle) { + if (!all_digests_supported(in_params)) + return KM_ERROR_UNSUPPORTED_DIGEST; + return unwrap(dev)->begin(unwrap(dev), purpose, key, in_params, out_params, + operation_handle); + } + + static keymaster_error_t update(const keymaster1_device_t* dev, + keymaster_operation_handle_t operation_handle, + const keymaster_key_param_set_t* in_params, + const keymaster_blob_t* input, size_t* input_consumed, + keymaster_key_param_set_t* out_params, + keymaster_blob_t* output) { + return unwrap(dev)->update(unwrap(dev), operation_handle, in_params, input, input_consumed, + out_params, output); + } + + static keymaster_error_t finish(const struct keymaster1_device* dev, // + keymaster_operation_handle_t operation_handle, + const keymaster_key_param_set_t* in_params, + const keymaster_blob_t* signature, + keymaster_key_param_set_t* out_params, + keymaster_blob_t* output) { + return unwrap(dev)->finish(unwrap(dev), operation_handle, in_params, signature, out_params, + output); + } + + static keymaster_error_t abort(const struct keymaster1_device* dev, + keymaster_operation_handle_t operation_handle) { + return unwrap(dev)->abort(unwrap(dev), operation_handle); + } + + private: + keymaster1_device_t device_; + const keymaster1_device_t* wrapped_device_; + hw_module_t new_module; + string new_module_name; +}; + +keymaster1_device_t* make_device_sha256_only(keymaster1_device_t* device) { + return (new Sha256OnlyWrapper(device))->keymaster_device(); +} + +} // namespace test +} // namespace keymaster diff --git a/unit_test/android_keymaster_test_utils.h b/unit_test/android_keymaster_test_utils.h new file mode 100644 index 0000000..5dd0f76 --- a/dev/null +++ b/unit_test/android_keymaster_test_utils.h @@ -0,0 +1,470 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSTEM_KEYMASTER_ANDROID_KEYMASTER_TEST_UTILS_H_ +#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_TEST_UTILS_H_ + +/* + * Utilities used to help with testing. Not used in production code. + */ + +#include <stdarg.h> + +#include <algorithm> +#include <memory> +#include <ostream> +#include <string> +#include <vector> + +#include <gtest/gtest.h> + +#include <hardware/keymaster0.h> +#include <hardware/keymaster1.h> +#include <hardware/keymaster2.h> +#include <hardware/keymaster_defs.h> + +#include <keymaster/android_keymaster_utils.h> +#include <keymaster/authorization_set.h> +#include <keymaster/keymaster_context.h> +#include <keymaster/logger.h> + +std::ostream& operator<<(std::ostream& os, const keymaster_key_param_t& param); +bool operator==(const keymaster_key_param_t& a, const keymaster_key_param_t& b); +std::string hex2str(std::string); + +namespace keymaster { + +bool operator==(const AuthorizationSet& a, const AuthorizationSet& b); +bool operator!=(const AuthorizationSet& a, const AuthorizationSet& b); + +std::ostream& operator<<(std::ostream& os, const AuthorizationSet& set); + +namespace test { + +template <keymaster_tag_t Tag, typename KeymasterEnum> +bool contains(const AuthorizationSet& set, TypedEnumTag<KM_ENUM, Tag, KeymasterEnum> tag, + KeymasterEnum val) { + int pos = set.find(tag); + return pos != -1 && static_cast<KeymasterEnum>(set[pos].enumerated) == val; +} + +template <keymaster_tag_t Tag, typename KeymasterEnum> +bool contains(const AuthorizationSet& set, TypedEnumTag<KM_ENUM_REP, Tag, KeymasterEnum> tag, + KeymasterEnum val) { + int pos = -1; + while ((pos = set.find(tag, pos)) != -1) + if (static_cast<KeymasterEnum>(set[pos].enumerated) == val) + return true; + return false; +} + +template <keymaster_tag_t Tag> +bool contains(const AuthorizationSet& set, TypedTag<KM_UINT, Tag> tag, uint32_t val) { + int pos = set.find(tag); + return pos != -1 && set[pos].integer == val; +} + +template <keymaster_tag_t Tag> +bool contains(const AuthorizationSet& set, TypedTag<KM_UINT_REP, Tag> tag, uint32_t val) { + int pos = -1; + while ((pos = set.find(tag, pos)) != -1) + if (set[pos].integer == val) + return true; + return false; +} + +template <keymaster_tag_t Tag> +bool contains(const AuthorizationSet& set, TypedTag<KM_ULONG, Tag> tag, uint64_t val) { + int pos = set.find(tag); + return pos != -1 && set[pos].long_integer == val; +} + +template <keymaster_tag_t Tag> +bool contains(const AuthorizationSet& set, TypedTag<KM_BYTES, Tag> tag, const std::string& val) { + int pos = set.find(tag); + return pos != -1 && + std::string(reinterpret_cast<const char*>(set[pos].blob.data), + set[pos].blob.data_length) == val; +} + +template <keymaster_tag_t Tag> +bool contains(const AuthorizationSet& set, TypedTag<KM_BIGNUM, Tag> tag, const std::string& val) { + int pos = set.find(tag); + return pos != -1 && + std::string(reinterpret_cast<const char*>(set[pos].blob.data), + set[pos].blob.data_length) == val; +} + +inline bool contains(const AuthorizationSet& set, keymaster_tag_t tag) { + return set.find(tag) != -1; +} + +class StdoutLogger : public Logger { + public: + StdoutLogger() { set_instance(this); } + + int log_msg(LogLevel level, const char* fmt, va_list args) const { + int output_len = 0; + switch (level) { + case DEBUG_LVL: + output_len = printf("DEBUG: "); + break; + case INFO_LVL: + output_len = printf("INFO: "); + break; + case WARNING_LVL: + output_len = printf("WARNING: "); + break; + case ERROR_LVL: + output_len = printf("ERROR: "); + break; + case SEVERE_LVL: + output_len = printf("SEVERE: "); + break; + } + + output_len += vprintf(fmt, args); + output_len += printf("\n"); + return output_len; + } +}; + +inline std::string make_string(const uint8_t* data, size_t length) { + return std::string(reinterpret_cast<const char*>(data), length); +} + +template <size_t N> std::string make_string(const uint8_t (&a)[N]) { + return make_string(a, N); +} + +/** + * Keymaster2TestInstance is used to parameterize Keymaster2Tests. Its main function is to create a + * keymaster2_device_t to which test calls can be directed. It also provides a place to specify + * various bits of alternative behavior, in cases where different devices are expected to behave + * differently (any such cases are a potential bug, but sometimes they may make sense). + */ +class Keymaster2TestInstanceCreator { + public: + virtual ~Keymaster2TestInstanceCreator(){}; + virtual keymaster2_device_t* CreateDevice() const = 0; + + virtual bool algorithm_in_km0_hardware(keymaster_algorithm_t algorithm) const = 0; + virtual int keymaster0_calls() const = 0; + virtual int minimal_digest_set() const { return false; } + virtual bool is_keymaster1_hw() const = 0; + virtual KeymasterContext* keymaster_context() const = 0; +}; + +// Use a shared_ptr because it's copyable. +typedef std::shared_ptr<Keymaster2TestInstanceCreator> InstanceCreatorPtr; + +const uint64_t OP_HANDLE_SENTINEL = 0xFFFFFFFFFFFFFFFF; +class Keymaster2Test : public testing::TestWithParam<InstanceCreatorPtr> { + protected: + Keymaster2Test(); + ~Keymaster2Test(); + + keymaster2_device_t* device(); + + keymaster_error_t GenerateKey(const AuthorizationSetBuilder& builder); + + keymaster_error_t DeleteKey(); + + keymaster_error_t ImportKey(const AuthorizationSetBuilder& builder, + keymaster_key_format_t format, const std::string& key_material); + + keymaster_error_t ExportKey(keymaster_key_format_t format, std::string* export_data); + + keymaster_error_t GetCharacteristics(); + + keymaster_error_t BeginOperation(keymaster_purpose_t purpose); + keymaster_error_t BeginOperation(keymaster_purpose_t purpose, const AuthorizationSet& input_set, + AuthorizationSet* output_set = NULL); + + keymaster_error_t UpdateOperation(const std::string& message, std::string* output, + size_t* input_consumed); + keymaster_error_t UpdateOperation(const AuthorizationSet& additional_params, + const std::string& message, AuthorizationSet* output_params, + std::string* output, size_t* input_consumed); + + keymaster_error_t FinishOperation(std::string* output); + keymaster_error_t FinishOperation(const std::string& signature, std::string* output); + keymaster_error_t FinishOperation(const AuthorizationSet& additional_params, + const std::string& signature, std::string* output) { + return FinishOperation(additional_params, signature, nullptr /* output_params */, output); + } + keymaster_error_t FinishOperation(const AuthorizationSet& additional_params, + const std::string& signature, AuthorizationSet* output_params, + std::string* output); + + keymaster_error_t AbortOperation(); + + keymaster_error_t AttestKey(const std::string& attest_challenge, keymaster_cert_chain_t* chain); + + keymaster_error_t UpgradeKey(const AuthorizationSet& upgrade_params); + + keymaster_error_t GetVersion(uint8_t* major, uint8_t* minor, uint8_t* subminor); + + std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message); + std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message, + const AuthorizationSet& begin_params, + const AuthorizationSet& update_params, + AuthorizationSet* output_params = NULL); + std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message, + const std::string& signature, const AuthorizationSet& begin_params, + const AuthorizationSet& update_params, + AuthorizationSet* output_params = NULL); + std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message, + const std::string& signature); + + void SignMessage(const std::string& message, std::string* signature, keymaster_digest_t digest); + void SignMessage(const std::string& message, std::string* signature, keymaster_digest_t digest, + keymaster_padding_t padding); + void MacMessage(const std::string& message, std::string* signature, size_t mac_length); + + void VerifyMessage(const std::string& message, const std::string& signature, + keymaster_digest_t digest); + void VerifyMessage(const std::string& message, const std::string& signature, + keymaster_digest_t digest, keymaster_padding_t padding); + void VerifyMac(const std::string& message, const std::string& signature); + + std::string EncryptMessage(const std::string& message, keymaster_padding_t padding, + std::string* generated_nonce = NULL); + std::string EncryptMessage(const std::string& message, keymaster_digest_t digest, + keymaster_padding_t padding, std::string* generated_nonce = NULL); + std::string EncryptMessage(const std::string& message, keymaster_block_mode_t block_mode, + keymaster_padding_t padding, std::string* generated_nonce = NULL); + std::string EncryptMessage(const AuthorizationSet& update_params, const std::string& message, + keymaster_digest_t digest, keymaster_padding_t padding, + std::string* generated_nonce = NULL); + std::string EncryptMessage(const AuthorizationSet& update_params, const std::string& message, + keymaster_block_mode_t block_mode, keymaster_padding_t padding, + std::string* generated_nonce = NULL); + std::string EncryptMessageWithParams(const std::string& message, + const AuthorizationSet& begin_params, + const AuthorizationSet& update_params, + AuthorizationSet* output_params); + + std::string DecryptMessage(const std::string& ciphertext, keymaster_padding_t padding); + std::string DecryptMessage(const std::string& ciphertext, keymaster_digest_t digest, + keymaster_padding_t padding); + std::string DecryptMessage(const std::string& ciphertext, keymaster_block_mode_t block_mode, + keymaster_padding_t padding); + std::string DecryptMessage(const std::string& ciphertext, keymaster_digest_t digest, + keymaster_padding_t padding, const std::string& nonce); + std::string DecryptMessage(const std::string& ciphertext, keymaster_block_mode_t block_mode, + keymaster_padding_t padding, const std::string& nonce); + std::string DecryptMessage(const AuthorizationSet& update_params, const std::string& ciphertext, + keymaster_digest_t digest, keymaster_padding_t padding, + const std::string& nonce); + std::string DecryptMessage(const AuthorizationSet& update_params, const std::string& ciphertext, + keymaster_block_mode_t block_mode, keymaster_padding_t padding, + const std::string& nonce); + + void CheckHmacTestVector(const std::string& key, const std::string& message, keymaster_digest_t digest, + std::string expected_mac); + void CheckAesOcbTestVector(const std::string& key, const std::string& nonce, + const std::string& associated_data, const std::string& message, + const std::string& expected_ciphertext); + void CheckAesCtrTestVector(const std::string& key, const std::string& nonce, + const std::string& message, const std::string& expected_ciphertext); + AuthorizationSet UserAuthParams(); + AuthorizationSet ClientParams(); + + template <typename T> + bool ResponseContains(const std::vector<T>& expected, const T* values, size_t len) { + return expected.size() == len && + std::is_permutation(values, values + len, expected.begin()); + } + + template <typename T> bool ResponseContains(T expected, const T* values, size_t len) { + return (len == 1 && *values == expected); + } + + AuthorizationSet hw_enforced(); + AuthorizationSet sw_enforced(); + + void FreeCharacteristics(); + void FreeKeyBlob(); + + void corrupt_key_blob(); + + void set_key_blob(const uint8_t* key, size_t key_length) { + FreeKeyBlob(); + blob_.key_material = key; + blob_.key_material_size = key_length; + } + + AuthorizationSet client_params() { + return AuthorizationSet(client_params_, sizeof(client_params_) / sizeof(client_params_[0])); + } + + private: + keymaster2_device_t* device_; + keymaster_blob_t client_id_ = {.data = reinterpret_cast<const uint8_t*>("app_id"), + .data_length = 6}; + keymaster_key_param_t client_params_[1] = { + Authorization(TAG_APPLICATION_ID, client_id_.data, client_id_.data_length)}; + + uint64_t op_handle_; + + keymaster_key_blob_t blob_; + keymaster_key_characteristics_t characteristics_; +}; + +struct Keymaster0CountingWrapper : public keymaster0_device_t { + explicit Keymaster0CountingWrapper(keymaster0_device_t* device) : device_(device), counter_(0) { + common = device_->common; + common.close = counting_close_device; + client_version = device_->client_version; + flags = device_->flags; + context = this; + + generate_keypair = counting_generate_keypair; + import_keypair = counting_import_keypair; + get_keypair_public = counting_get_keypair_public; + delete_keypair = counting_delete_keypair; + delete_all = counting_delete_all; + sign_data = counting_sign_data; + verify_data = counting_verify_data; + } + + int count() { return counter_; } + + // The blobs generated by the underlying softkeymaster start with "PK#8". Tweak the prefix so + // they don't get identified as softkeymaster blobs. + static void munge_blob(uint8_t* blob, size_t blob_length) { + if (blob && blob_length > 0 && *blob == 'P') + *blob = 'Q'; // Mind your Ps and Qs! + } + + // Copy and un-modfy the blob. The caller must clean up the return value. + static uint8_t* unmunge_blob(const uint8_t* blob, size_t blob_length) { + uint8_t* dup_blob = dup_buffer(blob, blob_length); + if (dup_blob && blob_length > 0 && *dup_blob == 'Q') + *dup_blob = 'P'; + return dup_blob; + } + + static keymaster0_device_t* device(const keymaster0_device_t* dev) { + Keymaster0CountingWrapper* wrapper = + reinterpret_cast<Keymaster0CountingWrapper*>(dev->context); + return wrapper->device_; + } + + static void increment(const keymaster0_device_t* dev) { + Keymaster0CountingWrapper* wrapper = + reinterpret_cast<Keymaster0CountingWrapper*>(dev->context); + wrapper->counter_++; + } + + static int counting_close_device(hw_device_t* dev) { + keymaster0_device_t* k0_dev = reinterpret_cast<keymaster0_device_t*>(dev); + increment(k0_dev); + Keymaster0CountingWrapper* wrapper = + reinterpret_cast<Keymaster0CountingWrapper*>(k0_dev->context); + int retval = + wrapper->device_->common.close(reinterpret_cast<hw_device_t*>(wrapper->device_)); + delete wrapper; + return retval; + } + + static int counting_generate_keypair(const struct keymaster0_device* dev, + const keymaster_keypair_t key_type, const void* key_params, + uint8_t** key_blob, size_t* key_blob_length) { + increment(dev); + int result = device(dev)->generate_keypair(device(dev), key_type, key_params, key_blob, + key_blob_length); + if (result == 0) + munge_blob(*key_blob, *key_blob_length); + return result; + } + + static int counting_import_keypair(const struct keymaster0_device* dev, const uint8_t* key, + const size_t key_length, uint8_t** key_blob, + size_t* key_blob_length) { + increment(dev); + int result = + device(dev)->import_keypair(device(dev), key, key_length, key_blob, key_blob_length); + if (result == 0) + munge_blob(*key_blob, *key_blob_length); + return result; + } + + static int counting_get_keypair_public(const struct keymaster0_device* dev, + const uint8_t* key_blob, const size_t key_blob_length, + uint8_t** x509_data, size_t* x509_data_length) { + increment(dev); + std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length)); + return device(dev)->get_keypair_public(device(dev), dup_blob.get(), key_blob_length, + x509_data, x509_data_length); + } + + static int counting_delete_keypair(const struct keymaster0_device* dev, const uint8_t* key_blob, + const size_t key_blob_length) { + increment(dev); + if (key_blob && key_blob_length > 0) + EXPECT_EQ('Q', *key_blob); + if (device(dev)->delete_keypair) { + std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length)); + return device(dev)->delete_keypair(device(dev), dup_blob.get(), key_blob_length); + } + return 0; + } + + static int counting_delete_all(const struct keymaster0_device* dev) { + increment(dev); + if (device(dev)->delete_all) + return device(dev)->delete_all(device(dev)); + return 0; + } + + static int counting_sign_data(const struct keymaster0_device* dev, const void* signing_params, + const uint8_t* key_blob, const size_t key_blob_length, + const uint8_t* data, const size_t data_length, + uint8_t** signed_data, size_t* signed_data_length) { + increment(dev); + std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length)); + return device(dev)->sign_data(device(dev), signing_params, dup_blob.get(), key_blob_length, + data, data_length, signed_data, signed_data_length); + } + + static int counting_verify_data(const struct keymaster0_device* dev, const void* signing_params, + const uint8_t* key_blob, const size_t key_blob_length, + const uint8_t* signed_data, const size_t signed_data_length, + const uint8_t* signature, const size_t signature_length) { + increment(dev); + std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length)); + return device(dev)->verify_data(device(dev), signing_params, dup_blob.get(), + key_blob_length, signed_data, signed_data_length, signature, + signature_length); + } + + private: + keymaster0_device_t* device_; + int counter_; +}; + +/** + * This function takes a keymaster1_device_t and wraps it in an adapter that supports only + * KM_DIGEST_SHA_2_256. + */ +keymaster1_device_t* make_device_sha256_only(keymaster1_device_t* device); + +} // namespace test +} // namespace keymaster + +#endif // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_TEST_UTILS_H_ diff --git a/unit_test/android_keymaster_utils.h b/unit_test/android_keymaster_utils.h new file mode 100644 index 0000000..b957dd1 --- a/dev/null +++ b/unit_test/android_keymaster_utils.h @@ -0,0 +1,306 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_ +#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_ + +#include <stdint.h> +#include <string.h> +#include <time.h> // for time_t. + +#include <UniquePtr.h> + +#include <hardware/keymaster_defs.h> +#include <keymaster/serializable.h> + +namespace keymaster { + +/** + * Convert the specified time value into "Java time", which is a signed 64-bit integer representing + * elapsed milliseconds since Jan 1, 1970. + */ +inline int64_t java_time(time_t time) { + // The exact meaning of a time_t value is implementation-dependent. If this code is ported to a + // platform that doesn't define it as "seconds since Jan 1, 1970 UTC", this function will have + // to be revised. + return time * 1000; +} + +/* + * Array Manipulation functions. This set of templated inline functions provides some nice tools + * for operating on c-style arrays. C-style arrays actually do have a defined size associated with + * them, as long as they are not allowed to decay to a pointer. These template methods exploit this + * to allow size-based array operations without explicitly specifying the size. If passed a pointer + * rather than an array, they'll fail to compile. + */ + +/** + * Return the size in bytes of the array \p a. + */ +template <typename T, size_t N> inline size_t array_size(const T(&a)[N]) { + return sizeof(a); +} + +/** + * Return the number of elements in array \p a. + */ +template <typename T, size_t N> inline size_t array_length(const T(&)[N]) { + return N; +} + +/** + * Duplicate the array \p a. The memory for the new array is allocated and the caller takes + * responsibility. + */ +template <typename T> inline T* dup_array(const T* a, size_t n) { + T* dup = new (std::nothrow) T[n]; + if (dup) + for (size_t i = 0; i < n; ++i) + dup[i] = a[i]; + return dup; +} + +/** + * Duplicate the array \p a. The memory for the new array is allocated and the caller takes + * responsibility. Note that the dup is necessarily returned as a pointer, so size is lost. Call + * array_length() on the original array to discover the size. + */ +template <typename T, size_t N> inline T* dup_array(const T(&a)[N]) { + return dup_array(a, N); +} + +/** + * Duplicate the buffer \p buf. The memory for the new buffer is allocated and the caller takes + * responsibility. + */ +uint8_t* dup_buffer(const void* buf, size_t size); + +/** + * Copy the contents of array \p arr to \p dest. + */ +template <typename T, size_t N> inline void copy_array(const T(&arr)[N], T* dest) { + for (size_t i = 0; i < N; ++i) + dest[i] = arr[i]; +} + +/** + * Search array \p a for value \p val, returning true if found. Note that this function is + * early-exit, meaning that it should not be used in contexts where timing analysis attacks could be + * a concern. + */ +template <typename T, size_t N> inline bool array_contains(const T(&a)[N], T val) { + for (size_t i = 0; i < N; ++i) { + if (a[i] == val) { + return true; + } + } + return false; +} + +/** + * Variant of memset() that uses GCC-specific pragmas to disable optimizations, so effect is not + * optimized away. This is important because we often need to wipe blocks of sensitive data from + * memory. As an additional convenience, this implementation avoids writing to NULL pointers. + */ +#ifdef __clang__ +#define OPTNONE __attribute__((optnone)) +#else // not __clang__ +#define OPTNONE __attribute__((optimize("O0"))) +#endif // not __clang__ +inline OPTNONE void* memset_s(void* s, int c, size_t n) { + if (!s) + return s; + return memset(s, c, n); +} +#undef OPTNONE + +/** + * Variant of memcmp that has the same runtime regardless of whether the data matches (i.e. doesn't + * short-circuit). Not an exact equivalent to memcmp because it doesn't return <0 if p1 < p2, just + * 0 for match and non-zero for non-match. + */ +int memcmp_s(const void* p1, const void* p2, size_t length); + +/** + * Eraser clears buffers. Construct it with a buffer or object and the destructor will ensure that + * it is zeroed. + */ +class Eraser { + public: + /* Not implemented. If this gets used, we want a link error. */ + template <typename T> explicit Eraser(T* t); + + template <typename T> + explicit Eraser(T& t) + : buf_(reinterpret_cast<uint8_t*>(&t)), size_(sizeof(t)) {} + + template <size_t N> explicit Eraser(uint8_t(&arr)[N]) : buf_(arr), size_(N) {} + + Eraser(void* buf, size_t size) : buf_(static_cast<uint8_t*>(buf)), size_(size) {} + ~Eraser() { memset_s(buf_, 0, size_); } + + private: + Eraser(const Eraser&); + void operator=(const Eraser&); + + uint8_t* buf_; + size_t size_; +}; + +/** + * ArrayWrapper is a trivial wrapper around a C-style array that provides begin() and end() + * methods. This is primarily to facilitate range-based iteration on arrays. It does not copy, nor + * does it take ownership; it just holds pointers. + */ +template <typename T> class ArrayWrapper { + public: + ArrayWrapper(T* array, size_t size) : begin_(array), end_(array + size) {} + + T* begin() { return begin_; } + T* end() { return end_; } + + private: + T* begin_; + T* end_; +}; + +/** + * Convert any unsigned integer from network to host order. We implement this here rather than + * using the functions from arpa/inet.h because the TEE doesn't have inet.h. This isn't the most + * efficient implementation, but the compiler should unroll the loop and tighten it up. + */ +template <typename T> T ntoh(T t) { + const uint8_t* byte_ptr = reinterpret_cast<const uint8_t*>(&t); + T retval = 0; + for (size_t i = 0; i < sizeof(t); ++i) { + retval <<= 8; + retval |= byte_ptr[i]; + } + return retval; +} + +/** + * Convert any unsigned integer from host to network order. We implement this here rather than + * using the functions from arpa/inet.h because the TEE doesn't have inet.h. This isn't the most + * efficient implementation, but the compiler should unroll the loop and tighten it up. + */ +template <typename T> T hton(T t) { + T retval; + uint8_t* byte_ptr = reinterpret_cast<uint8_t*>(&retval); + for (size_t i = sizeof(t); i > 0; --i) { + byte_ptr[i - 1] = t & 0xFF; + t >>= 8; + } + return retval; +} + +/** + * KeymasterKeyBlob is a very simple extension of the C struct keymaster_key_blob_t. It manages its + * own memory, which makes avoiding memory leaks much easier. + */ +struct KeymasterKeyBlob : public keymaster_key_blob_t { + KeymasterKeyBlob() { + key_material = nullptr; + key_material_size = 0; + } + + KeymasterKeyBlob(const uint8_t* data, size_t size) { + key_material_size = 0; + key_material = dup_buffer(data, size); + if (key_material) + key_material_size = size; + } + + explicit KeymasterKeyBlob(size_t size) { + key_material_size = 0; + key_material = new (std::nothrow) uint8_t[size]; + if (key_material) + key_material_size = size; + } + + explicit KeymasterKeyBlob(const keymaster_key_blob_t& blob) { + key_material_size = 0; + key_material = dup_buffer(blob.key_material, blob.key_material_size); + if (key_material) + key_material_size = blob.key_material_size; + } + + KeymasterKeyBlob(const KeymasterKeyBlob& blob) { + key_material_size = 0; + key_material = dup_buffer(blob.key_material, blob.key_material_size); + if (key_material) + key_material_size = blob.key_material_size; + } + + void operator=(const KeymasterKeyBlob& blob) { + Clear(); + key_material = dup_buffer(blob.key_material, blob.key_material_size); + key_material_size = blob.key_material_size; + } + + ~KeymasterKeyBlob() { Clear(); } + + const uint8_t* begin() const { return key_material; } + const uint8_t* end() const { return key_material + key_material_size; } + + void Clear() { + memset_s(const_cast<uint8_t*>(key_material), 0, key_material_size); + delete[] key_material; + key_material = nullptr; + key_material_size = 0; + } + + const uint8_t* Reset(size_t new_size) { + Clear(); + key_material = new (std::nothrow) uint8_t[new_size]; + if (key_material) + key_material_size = new_size; + return key_material; + } + + // The key_material in keymaster_key_blob_t is const, which is the right thing in most + // circumstances, but occasionally we do need to write into it. This method exposes a non-const + // version of the pointer. Use sparingly. + uint8_t* writable_data() { return const_cast<uint8_t*>(key_material); } + + keymaster_key_blob_t release() { + keymaster_key_blob_t tmp = {key_material, key_material_size}; + key_material = nullptr; + key_material_size = 0; + return tmp; + } + + size_t SerializedSize() const { return sizeof(uint32_t) + key_material_size; } + uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const { + return append_size_and_data_to_buf(buf, end, key_material, key_material_size); + } + + bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) { + Clear(); + UniquePtr<uint8_t[]> tmp; + if (!copy_size_and_data_from_buf(buf_ptr, end, &key_material_size, &tmp)) { + key_material = nullptr; + key_material_size = 0; + return false; + } + key_material = tmp.release(); + return true; + } +}; + +} // namespace keymaster + +#endif // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_ diff --git a/unit_test/attestation_record.cpp b/unit_test/attestation_record.cpp new file mode 100644 index 0000000..8ba5a8a --- a/dev/null +++ b/unit_test/attestation_record.cpp @@ -0,0 +1,690 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "attestation_record.h" + +#include <assert.h> + +#include <openssl/asn1t.h> + +#include "openssl_err.h" +#include "openssl_utils.h" + +#include <keymaster/android_keymaster_utils.h> +#include <keymaster/keymaster_context.h> + +namespace keymaster { + +struct stack_st_ASN1_TYPE_Delete { + void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); } +}; + +struct ASN1_STRING_Delete { + void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); } +}; + +struct ASN1_TYPE_Delete { + void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); } +}; + +#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER) + +typedef struct km_root_of_trust { + ASN1_OCTET_STRING* verified_boot_key; + ASN1_BOOLEAN* device_locked; + ASN1_ENUMERATED* verified_boot_state; +} KM_ROOT_OF_TRUST; + +ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = { + ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING), + ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN), + ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED), +} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST); +IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST); + +typedef struct km_auth_list { + ASN1_INTEGER_SET* purpose; + ASN1_INTEGER* algorithm; + ASN1_INTEGER* key_size; + ASN1_INTEGER_SET* digest; + ASN1_INTEGER_SET* padding; + ASN1_INTEGER_SET* kdf; + ASN1_INTEGER* ec_curve; + ASN1_INTEGER* rsa_public_exponent; + ASN1_INTEGER* active_date_time; + ASN1_INTEGER* origination_expire_date_time; + ASN1_INTEGER* usage_expire_date_time; + ASN1_NULL* no_auth_required; + ASN1_INTEGER* user_auth_type; + ASN1_INTEGER* auth_timeout; + ASN1_NULL* allow_while_on_body; + ASN1_NULL* all_applications; + ASN1_OCTET_STRING* application_id; + ASN1_INTEGER* creation_date_time; + ASN1_INTEGER* origin; + ASN1_NULL* rollback_resistant; + KM_ROOT_OF_TRUST* root_of_trust; + ASN1_INTEGER* os_version; + ASN1_INTEGER* os_patchlevel; +} KM_AUTH_LIST; + +ASN1_SEQUENCE(KM_AUTH_LIST) = { + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.masked_tag()), + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.masked_tag()), + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.masked_tag()), + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, kdf, ASN1_INTEGER, TAG_KDF.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER, + TAG_RSA_PUBLIC_EXPONENT.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER, + TAG_ORIGINATION_EXPIRE_DATETIME.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER, + TAG_USAGE_EXPIRE_DATETIME.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL, + TAG_ALLOW_WHILE_ON_BODY.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, all_applications, ASN1_NULL, TAG_ALL_APPLICATIONS.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, application_id, ASN1_OCTET_STRING, TAG_APPLICATION_ID.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER, + TAG_CREATION_DATETIME.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistant, ASN1_NULL, TAG_ROLLBACK_RESISTANT.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.masked_tag()), + ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.masked_tag()), +} ASN1_SEQUENCE_END(KM_AUTH_LIST); +IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST); + +typedef struct km_key_description { + ASN1_INTEGER* attestation_version; + ASN1_ENUMERATED* attestation_security_level; + ASN1_INTEGER* keymaster_version; + ASN1_ENUMERATED* keymaster_security_level; + ASN1_OCTET_STRING* attestation_challenge; + KM_AUTH_LIST* software_enforced; + KM_AUTH_LIST* tee_enforced; + ASN1_INTEGER* unique_id; +} KM_KEY_DESCRIPTION; + +ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = { + ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_version, ASN1_INTEGER), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_security_level, ASN1_ENUMERATED), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST), +} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION); +IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION); + +struct KM_AUTH_LIST_Delete { + void operator()(KM_AUTH_LIST* p) { KM_AUTH_LIST_free(p); } +}; + +struct KM_KEY_DESCRIPTION_Delete { + void operator()(KM_KEY_DESCRIPTION* p) { KM_KEY_DESCRIPTION_free(p); } +}; + +static uint32_t get_uint32_value(const keymaster_key_param_t& param) { + switch (keymaster_tag_get_type(param.tag)) { + case KM_ENUM: + case KM_ENUM_REP: + return param.enumerated; + case KM_UINT: + case KM_UINT_REP: + return param.integer; + default: + assert(false); + return 0xFFFFFFFF; + } +} + +// Insert value in either the dest_integer or the dest_integer_set, whichever is provided. +static keymaster_error_t insert_integer(ASN1_INTEGER* value, ASN1_INTEGER** dest_integer, + ASN1_INTEGER_SET** dest_integer_set) { + assert((dest_integer == nullptr) ^ (dest_integer_set == nullptr)); + assert(value); + + if (dest_integer_set) { + if (!*dest_integer_set) + *dest_integer_set = sk_ASN1_INTEGER_new_null(); + if (!*dest_integer_set) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + if (!sk_ASN1_INTEGER_push(*dest_integer_set, value)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + return KM_ERROR_OK; + + } else if (dest_integer) { + if (*dest_integer) + ASN1_INTEGER_free(*dest_integer); + *dest_integer = value; + return KM_ERROR_OK; + } + + assert(false); // Should never get here. + return KM_ERROR_OK; +} + +// Put the contents of the keymaster AuthorizationSet auth_list in to the ASN.1 record structure, +// record. +static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_AUTH_LIST* record) { + assert(record); + + if (auth_list.empty()) + return KM_ERROR_OK; + + for (auto entry : auth_list) { + + ASN1_INTEGER_SET** integer_set = nullptr; + ASN1_INTEGER** integer_ptr = nullptr; + ASN1_OCTET_STRING** string_ptr = nullptr; + ASN1_NULL** bool_ptr = nullptr; + + switch (entry.tag) { + + /* Ignored tags */ + case KM_TAG_INVALID: + case KM_TAG_ASSOCIATED_DATA: + case KM_TAG_NONCE: + case KM_TAG_AUTH_TOKEN: + case KM_TAG_MAC_LENGTH: + case KM_TAG_ALL_USERS: + case KM_TAG_USER_ID: + case KM_TAG_USER_SECURE_ID: + case KM_TAG_EXPORTABLE: + case KM_TAG_RESET_SINCE_ID_ROTATION: + case KM_TAG_ATTESTATION_CHALLENGE: + case KM_TAG_BLOCK_MODE: + case KM_TAG_CALLER_NONCE: + case KM_TAG_MIN_MAC_LENGTH: + case KM_TAG_ECIES_SINGLE_HASH_MODE: + case KM_TAG_INCLUDE_UNIQUE_ID: + case KM_TAG_BLOB_USAGE_REQUIREMENTS: + case KM_TAG_BOOTLOADER_ONLY: + case KM_TAG_MIN_SECONDS_BETWEEN_OPS: + case KM_TAG_MAX_USES_PER_BOOT: + case KM_TAG_APPLICATION_DATA: + case KM_TAG_UNIQUE_ID: + case KM_TAG_ROOT_OF_TRUST: + continue; + + /* Non-repeating enumerations */ + case KM_TAG_ALGORITHM: + integer_ptr = &record->algorithm; + break; + case KM_TAG_EC_CURVE: + integer_ptr = &record->ec_curve; + break; + case KM_TAG_USER_AUTH_TYPE: + integer_ptr = &record->user_auth_type; + break; + case KM_TAG_ORIGIN: + integer_ptr = &record->origin; + break; + + /* Repeating enumerations */ + case KM_TAG_PURPOSE: + integer_set = &record->purpose; + break; + case KM_TAG_PADDING: + integer_set = &record->padding; + break; + case KM_TAG_DIGEST: + integer_set = &record->digest; + break; + case KM_TAG_KDF: + integer_set = &record->kdf; + break; + + /* Non-repeating unsigned integers */ + case KM_TAG_KEY_SIZE: + integer_ptr = &record->key_size; + break; + case KM_TAG_AUTH_TIMEOUT: + integer_ptr = &record->auth_timeout; + break; + case KM_TAG_OS_VERSION: + integer_ptr = &record->os_version; + break; + case KM_TAG_OS_PATCHLEVEL: + integer_ptr = &record->os_patchlevel; + break; + + /* Non-repeating long unsigned integers */ + case KM_TAG_RSA_PUBLIC_EXPONENT: + integer_ptr = &record->rsa_public_exponent; + break; + + /* Dates */ + case KM_TAG_ACTIVE_DATETIME: + integer_ptr = &record->active_date_time; + break; + case KM_TAG_ORIGINATION_EXPIRE_DATETIME: + integer_ptr = &record->origination_expire_date_time; + break; + case KM_TAG_USAGE_EXPIRE_DATETIME: + integer_ptr = &record->usage_expire_date_time; + break; + case KM_TAG_CREATION_DATETIME: + integer_ptr = &record->creation_date_time; + break; + + /* Booleans */ + case KM_TAG_NO_AUTH_REQUIRED: + bool_ptr = &record->no_auth_required; + break; + case KM_TAG_ALL_APPLICATIONS: + bool_ptr = &record->all_applications; + break; + case KM_TAG_ROLLBACK_RESISTANT: + bool_ptr = &record->rollback_resistant; + break; + case KM_TAG_ALLOW_WHILE_ON_BODY: + bool_ptr = &record->allow_while_on_body; + break; + + /* Byte arrays*/ + case KM_TAG_APPLICATION_ID: + string_ptr = &record->application_id; + break; + default: + break; + } + + keymaster_tag_type_t type = keymaster_tag_get_type(entry.tag); + switch (type) { + case KM_ENUM: + case KM_ENUM_REP: + case KM_UINT: + case KM_UINT_REP: { + assert((keymaster_tag_repeatable(entry.tag) && integer_set) || + (!keymaster_tag_repeatable(entry.tag) && integer_ptr)); + + UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(ASN1_INTEGER_new()); + if (!value.get()) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + if (!ASN1_INTEGER_set(value.get(), get_uint32_value(entry))) + return TranslateLastOpenSslError(); + + insert_integer(value.release(), integer_ptr, integer_set); + break; + } + + case KM_ULONG: + case KM_ULONG_REP: + case KM_DATE: { + assert((keymaster_tag_repeatable(entry.tag) && integer_set) || + (!keymaster_tag_repeatable(entry.tag) && integer_ptr)); + + UniquePtr<BIGNUM, BIGNUM_Delete> bn_value(BN_new()); + if (!bn_value.get()) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + if (type == KM_DATE) { + if (!BN_set_u64(bn_value.get(), entry.date_time)) { + return TranslateLastOpenSslError(); + } + } else { + if (!BN_set_u64(bn_value.get(), entry.long_integer)) { + return TranslateLastOpenSslError(); + } + } + + UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value( + BN_to_ASN1_INTEGER(bn_value.get(), nullptr)); + if (!value.get()) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + insert_integer(value.release(), integer_ptr, integer_set); + break; + } + + case KM_BOOL: + assert(bool_ptr); + if (!*bool_ptr) + *bool_ptr = ASN1_NULL_new(); + if (!*bool_ptr) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + break; + + /* Byte arrays*/ + case KM_BYTES: + assert(string_ptr); + if (!*string_ptr) + *string_ptr = ASN1_OCTET_STRING_new(); + if (!*string_ptr) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + if (!ASN1_OCTET_STRING_set(*string_ptr, entry.blob.data, entry.blob.data_length)) + return TranslateLastOpenSslError(); + break; + + default: + return KM_ERROR_UNIMPLEMENTED; + } + } + + keymaster_ec_curve_t ec_curve; + uint32_t key_size; + if (auth_list.Contains(TAG_ALGORITHM, KM_ALGORITHM_EC) && // + !auth_list.Contains(TAG_EC_CURVE) && // + auth_list.GetTagValue(TAG_KEY_SIZE, &key_size)) { + // This must be a keymaster1 key. It's an EC key with no curve. Insert the curve. + + keymaster_error_t error = EcKeySizeToCurve(key_size, &ec_curve); + if (error != KM_ERROR_OK) + return error; + + UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(ASN1_INTEGER_new()); + if (!value.get()) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + if (!ASN1_INTEGER_set(value.get(), ec_curve)) + return TranslateLastOpenSslError(); + + insert_integer(value.release(), &record->ec_curve, nullptr); + } + + return KM_ERROR_OK; +} + +// Construct an ASN1.1 DER-encoded attestation record containing the values from sw_enforced and +// tee_enforced. +keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_params, + const AuthorizationSet& sw_enforced, + const AuthorizationSet& tee_enforced, + const KeymasterContext& context, + UniquePtr<uint8_t[]>* asn1_key_desc, + size_t* asn1_key_desc_len) { + assert(asn1_key_desc && asn1_key_desc_len); + + UniquePtr<KM_KEY_DESCRIPTION, KM_KEY_DESCRIPTION_Delete> key_desc(KM_KEY_DESCRIPTION_new()); + if (!key_desc.get()) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + keymaster_security_level_t keymaster_security_level; + uint32_t keymaster_version = UINT32_MAX; + if (tee_enforced.empty()) { + // Software key. + keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE; + keymaster_version = 2; + } else { + keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT; + switch (context.GetSecurityLevel()) { + case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT: + // We're running in a TEE, so the key is KM2. + keymaster_version = 2; + break; + + case KM_SECURITY_LEVEL_SOFTWARE: + // We're running in software, wrapping some KM hardware. Is it KM0 or KM1? KM1 keys + // have the purpose in the tee_enforced list. It's possible that a key could be created + // without a purpose, which would fool this test into reporting it's a KM0 key. That + // corner case doesn't matter much, because purpose-less keys are not usable anyway. + // Also, KM1 TEEs should disappear rapidly. + keymaster_version = tee_enforced.Contains(TAG_PURPOSE) ? 1 : 0; + break; + } + + if (keymaster_version == UINT32_MAX) + return KM_ERROR_UNKNOWN_ERROR; + } + + if (!ASN1_INTEGER_set(key_desc->attestation_version, 1) || + !ASN1_ENUMERATED_set(key_desc->attestation_security_level, context.GetSecurityLevel()) || + !ASN1_INTEGER_set(key_desc->keymaster_version, keymaster_version) || + !ASN1_ENUMERATED_set(key_desc->keymaster_security_level, keymaster_security_level)) + return TranslateLastOpenSslError(); + + keymaster_blob_t attestation_challenge = {nullptr, 0}; + if (!attestation_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge)) + return KM_ERROR_ATTESTATION_CHALLENGE_MISSING; + if (!ASN1_OCTET_STRING_set(key_desc->attestation_challenge, attestation_challenge.data, + attestation_challenge.data_length)) + return TranslateLastOpenSslError(); + + keymaster_error_t error = build_auth_list(sw_enforced, key_desc->software_enforced); + if (error != KM_ERROR_OK) + return error; + + error = build_auth_list(tee_enforced, key_desc->tee_enforced); + if (error != KM_ERROR_OK) + return error; + + // Only check tee_enforced for TAG_INCLUDE_UNIQUE_ID. If we don't have hardware we can't + // generate unique IDs. + if (tee_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID)) { + uint64_t creation_datetime; + // Only check sw_enforced for TAG_CREATION_DATETIME, since it shouldn't be in tee_enforced, + // since this implementation has no secure wall clock. + if (!sw_enforced.GetTagValue(TAG_CREATION_DATETIME, &creation_datetime)) { + LOG_E("Unique ID cannot be created without creation datetime", 0); + return KM_ERROR_INVALID_KEY_BLOB; + } + + keymaster_blob_t application_id = {nullptr, 0}; + sw_enforced.GetTagValue(TAG_APPLICATION_ID, &application_id); + + Buffer unique_id; + error = context.GenerateUniqueId( + creation_datetime, application_id, + attestation_params.GetTagValue(TAG_RESET_SINCE_ID_ROTATION), &unique_id); + if (error != KM_ERROR_OK) + return error; + + key_desc->unique_id = ASN1_OCTET_STRING_new(); + if (!key_desc->unique_id || + !ASN1_OCTET_STRING_set(key_desc->unique_id, unique_id.peek_read(), + unique_id.available_read())) + return TranslateLastOpenSslError(); + } + + int len = i2d_KM_KEY_DESCRIPTION(key_desc.get(), nullptr); + if (len < 0) + return TranslateLastOpenSslError(); + *asn1_key_desc_len = len; + asn1_key_desc->reset(new uint8_t[*asn1_key_desc_len]); + if (!asn1_key_desc->get()) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + uint8_t* p = asn1_key_desc->get(); + len = i2d_KM_KEY_DESCRIPTION(key_desc.get(), &p); + if (len < 0) + return TranslateLastOpenSslError(); + + return KM_ERROR_OK; +} + +// Copy all enumerated values with the specified tag from stack to auth_list. +static bool get_repeated_enums(const stack_st_ASN1_INTEGER* stack, keymaster_tag_t tag, + AuthorizationSet* auth_list) { + assert(keymaster_tag_get_type(tag) == KM_ENUM_REP); + for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) { + if (!auth_list->push_back( + keymaster_param_enum(tag, ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i))))) + return false; + } + return true; +} + +// Add the specified integer tag/value pair to auth_list. +template <keymaster_tag_type_t Type, keymaster_tag_t Tag, typename KeymasterEnum> +static bool get_enum(const ASN1_INTEGER* asn1_int, TypedEnumTag<Type, Tag, KeymasterEnum> tag, + AuthorizationSet* auth_list) { + if (!asn1_int) + return true; + return auth_list->push_back(tag, static_cast<KeymasterEnum>(ASN1_INTEGER_get(asn1_int))); +} + +// Add the specified ulong tag/value pair to auth_list. +static bool get_ulong(const ASN1_INTEGER* asn1_int, keymaster_tag_t tag, + AuthorizationSet* auth_list) { + if (!asn1_int) + return true; + UniquePtr<BIGNUM, BIGNUM_Delete> bn(ASN1_INTEGER_to_BN(asn1_int, nullptr)); + if (!bn.get()) + return false; + uint64_t ulong = BN_get_word(bn.get()); + return auth_list->push_back(keymaster_param_long(tag, ulong)); +} + +// Extract the values from the specified ASN.1 record and place them in auth_list. +static keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record, + AuthorizationSet* auth_list) { + if (!record) + return KM_ERROR_OK; + + // Purpose + if (!get_repeated_enums(record->purpose, TAG_PURPOSE, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Algorithm + if (!get_enum(record->algorithm, TAG_ALGORITHM, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Key size + if (record->key_size && !auth_list->push_back(TAG_KEY_SIZE, ASN1_INTEGER_get(record->key_size))) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Digest + if (!get_repeated_enums(record->digest, TAG_DIGEST, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Padding + if (!get_repeated_enums(record->padding, TAG_PADDING, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // EC curve + if (!get_enum(record->ec_curve, TAG_EC_CURVE, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // RSA public exponent + if (!get_ulong(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Active date time + if (!get_ulong(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Origination expire date time + if (!get_ulong(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, + auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Usage Expire date time + if (!get_ulong(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // No auth required + if (record->no_auth_required && !auth_list->push_back(TAG_NO_AUTH_REQUIRED)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // User auth type + if (!get_enum(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Auth timeout + if (record->auth_timeout && + !auth_list->push_back(TAG_AUTH_TIMEOUT, ASN1_INTEGER_get(record->auth_timeout))) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // All applications + if (record->all_applications && !auth_list->push_back(TAG_ALL_APPLICATIONS)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Application ID + if (record->application_id && + !auth_list->push_back(TAG_APPLICATION_ID, record->application_id->data, + record->application_id->length)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Creation date time + if (!get_ulong(record->creation_date_time, TAG_CREATION_DATETIME, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Origin + if (!get_enum(record->origin, TAG_ORIGIN, auth_list)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Rollback resistant + if (record->rollback_resistant && !auth_list->push_back(TAG_ROLLBACK_RESISTANT)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // Root of trust + if (record->root_of_trust) { + KM_ROOT_OF_TRUST* rot = record->root_of_trust; + if (!rot->verified_boot_key) + return KM_ERROR_INVALID_KEY_BLOB; + + // Other root of trust fields are not mapped to auth set entries. + } + + // OS Version + if (record->os_version && + !auth_list->push_back(TAG_OS_VERSION, ASN1_INTEGER_get(record->os_version))) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + // OS Patch level + if (record->os_patchlevel && + !auth_list->push_back(TAG_OS_PATCHLEVEL, ASN1_INTEGER_get(record->os_patchlevel))) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + return KM_ERROR_OK; +} + +// Parse the DER-encoded attestation record, placing the results in keymaster_version, +// attestation_challenge, software_enforced, tee_enforced and unique_id. +keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len, + uint32_t* attestation_version, // + keymaster_security_level_t* attestation_security_level, + uint32_t* keymaster_version, + keymaster_security_level_t* keymaster_security_level, + keymaster_blob_t* attestation_challenge, + AuthorizationSet* software_enforced, + AuthorizationSet* tee_enforced, + keymaster_blob_t* unique_id) { + const uint8_t* p = asn1_key_desc; + UniquePtr<KM_KEY_DESCRIPTION, KM_KEY_DESCRIPTION_Delete> record( + d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len)); + if (!record.get()) + return TranslateLastOpenSslError(); + + *attestation_version = ASN1_INTEGER_get(record->attestation_version); + *attestation_security_level = static_cast<keymaster_security_level_t>( + ASN1_ENUMERATED_get(record->attestation_security_level)); + *keymaster_version = ASN1_INTEGER_get(record->keymaster_version); + *keymaster_security_level = static_cast<keymaster_security_level_t>( + ASN1_ENUMERATED_get(record->keymaster_security_level)); + + attestation_challenge->data = + dup_buffer(record->attestation_challenge->data, record->attestation_challenge->length); + attestation_challenge->data_length = record->attestation_challenge->length; + + unique_id->data = dup_buffer(record->unique_id->data, record->unique_id->length); + unique_id->data_length = record->unique_id->length; + + keymaster_error_t error = extract_auth_list(record->software_enforced, software_enforced); + if (error != KM_ERROR_OK) + return error; + + return extract_auth_list(record->tee_enforced, tee_enforced); +} + +} // namepace keymaster diff --git a/unit_test/attestation_record.h b/unit_test/attestation_record.h new file mode 100644 index 0000000..64acabc --- a/dev/null +++ b/unit_test/attestation_record.h @@ -0,0 +1,62 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSTEM_KEYMASTER_ATTESTATION_RECORD_H_ +#define SYSTEM_KEYMASTER_ATTESTATION_RECORD_H_ + +#include <hardware/keymaster_defs.h> + +#include <keymaster/authorization_set.h> + +namespace keymaster { + +class KeymasterContext; + +/** + * The OID for Android attestation records. For the curious, it breaks down as follows: + * + * 1 = ISO + * 3 = org + * 6 = DoD (Huh? OIDs are weird.) + * 1 = IANA + * 4 = Private + * 1 = Enterprises + * 11129 = Google + * 2 = Google security + * 1 = certificate extension + * 17 = Android attestation extension. + */ +static const char kAttestionRecordOid[] = "1.3.6.1.4.1.11129.2.1.17"; + +keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_params, + const AuthorizationSet& software_enforced, + const AuthorizationSet& tee_enforced, + const KeymasterContext& context, + UniquePtr<uint8_t[]>* asn1_key_desc, + size_t* asn1_key_desc_len); + +keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len, + uint32_t* attestation_version, // + keymaster_security_level_t* attestation_security_level, + uint32_t* keymaster_version, + keymaster_security_level_t* keymaster_security_level, + keymaster_blob_t* attestation_challenge, + AuthorizationSet* software_enforced, + AuthorizationSet* tee_enforced, + keymaster_blob_t* unique_id); +} + +#endif // SYSTEM_KEYMASTER_ATTESTATION_RECORD_H_ diff --git a/unit_test/attestation_record_test.cpp b/unit_test/attestation_record_test.cpp new file mode 100644 index 0000000..1cf8630 --- a/dev/null +++ b/unit_test/attestation_record_test.cpp @@ -0,0 +1,145 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fstream> + +#include <gtest/gtest.h> + +#include <keymaster/keymaster_context.h> + +#include "android_keymaster_test_utils.h" +#include "attestation_record.h" + +#include <keymaster/keymaster_context.h> + +namespace keymaster { +namespace test { + +class TestContext : public KeymasterContext { + public: + keymaster_security_level_t GetSecurityLevel() const override { + return KM_SECURITY_LEVEL_SOFTWARE; + } + keymaster_error_t SetSystemVersion(uint32_t /* os_version */, + uint32_t /* os_patchlevel */) override { + return KM_ERROR_UNIMPLEMENTED; + } + void GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const override { + *os_version = 0; + *os_patchlevel = 0; + } + KeyFactory* GetKeyFactory(keymaster_algorithm_t /* algorithm */) const override { + return nullptr; + } + OperationFactory* GetOperationFactory(keymaster_algorithm_t /* algorithm */, + keymaster_purpose_t /* purpose */) const override { + return nullptr; + } + keymaster_algorithm_t* GetSupportedAlgorithms(size_t* /* algorithms_count */) const override { + return nullptr; + } + keymaster_error_t CreateKeyBlob(const AuthorizationSet& /* key_description */, + keymaster_key_origin_t /* origin */, + const KeymasterKeyBlob& /* key_material */, + KeymasterKeyBlob* /* blob */, + AuthorizationSet* /* hw_enforced */, + AuthorizationSet* /* sw_enforced */) const override { + return KM_ERROR_UNIMPLEMENTED; + } + keymaster_error_t UpgradeKeyBlob(const KeymasterKeyBlob& /* key_to_upgrade */, + const AuthorizationSet& /* upgrade_params */, + KeymasterKeyBlob* /* upgraded_key */) const override { + return KM_ERROR_UNIMPLEMENTED; + } + keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& /* blob */, + const AuthorizationSet& /* additional_params */, + KeymasterKeyBlob* /* key_material */, + AuthorizationSet* /* hw_enforced */, + AuthorizationSet* /* sw_enforced */) const override { + return KM_ERROR_UNIMPLEMENTED; + } + keymaster_error_t AddRngEntropy(const uint8_t* /* buf */, size_t /* length */) const override { + return KM_ERROR_UNIMPLEMENTED; + } + keymaster_error_t GenerateRandom(uint8_t* /* buf */, size_t /* length */) const override { + return KM_ERROR_UNIMPLEMENTED; + } + KeymasterEnforcement* enforcement_policy() { return nullptr; } + EVP_PKEY* AttestationKey(keymaster_algorithm_t /* algorithm */, + keymaster_error_t* /* error */) const override { + return nullptr; + } + keymaster_cert_chain_t* AttestationChain(keymaster_algorithm_t /* algorithm */, + keymaster_error_t* /* error */) const override { + return nullptr; + } + keymaster_error_t GenerateUniqueId(uint64_t /* creation_date_time */, + const keymaster_blob_t& /* application_id */, + bool /* reset_since_rotation */, Buffer* unique_id) const { + // Finally, the reason for defining this class: + unique_id->Reinitialize("foo", 3); + return KM_ERROR_OK; + } +}; + +TEST(AttestTest, Simple) { + AuthorizationSet hw_set(AuthorizationSetBuilder() + .RsaSigningKey(512, 3) + .Digest(KM_DIGEST_SHA_2_256) + .Digest(KM_DIGEST_SHA_2_384) + .Authorization(TAG_OS_VERSION, 60000) + .Authorization(TAG_OS_PATCHLEVEL, 201512) + .Authorization(TAG_APPLICATION_ID, "bar", 3)); + AuthorizationSet sw_set(AuthorizationSetBuilder().Authorization(TAG_ACTIVE_DATETIME, 10)); + + UniquePtr<uint8_t[]> asn1; + size_t asn1_len; + AuthorizationSet attest_params( + AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_CHALLENGE, "hello", 5)); + EXPECT_EQ(KM_ERROR_OK, build_attestation_record(attest_params, sw_set, hw_set, TestContext(), + &asn1, &asn1_len)); + EXPECT_GT(asn1_len, 0U); + + std::ofstream output("attest.der", + std::ofstream::out | std::ofstream::binary | std::ofstream::trunc); + if (output) + output.write(reinterpret_cast<const char*>(asn1.get()), asn1_len); + output.close(); + + AuthorizationSet parsed_hw_set; + AuthorizationSet parsed_sw_set; + uint32_t attestation_version; + uint32_t keymaster_version; + keymaster_security_level_t attestation_security_level; + keymaster_security_level_t keymaster_security_level; + keymaster_blob_t attestation_challenge = {}; + keymaster_blob_t unique_id = {}; + EXPECT_EQ(KM_ERROR_OK, + parse_attestation_record(asn1.get(), asn1_len, &attestation_version, + &attestation_security_level, &keymaster_version, + &keymaster_security_level, &attestation_challenge, + &parsed_sw_set, &parsed_hw_set, &unique_id)); + + hw_set.Sort(); + sw_set.Sort(); + parsed_hw_set.Sort(); + parsed_sw_set.Sort(); + EXPECT_EQ(hw_set, parsed_hw_set); + EXPECT_EQ(sw_set, parsed_sw_set); +} + +} // namespace test +} // namespace keymaster diff --git a/unit_test/authorization_set_test.cpp b/unit_test/authorization_set_test.cpp new file mode 100644 index 0000000..f3f4412 --- a/dev/null +++ b/unit_test/authorization_set_test.cpp @@ -0,0 +1,745 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> + +#include <keymaster/authorization_set.h> +#include <keymaster/android_keymaster_utils.h> + +#include "android_keymaster_test_utils.h" + +namespace keymaster { + +namespace test { + +TEST(Construction, ListProvided) { + keymaster_key_param_t params[] = { + Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), + Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_USER_ID, 7), + Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD), + Authorization(TAG_APPLICATION_ID, "my_app", 6), Authorization(TAG_KEY_SIZE, 256), + Authorization(TAG_AUTH_TIMEOUT, 300), + }; + AuthorizationSet set(params, array_length(params)); + EXPECT_EQ(8U, set.size()); +} + +TEST(Construction, Copy) { + keymaster_key_param_t params[] = { + Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), + Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_USER_ID, 7), + Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD), + Authorization(TAG_APPLICATION_ID, "my_app", 6), Authorization(TAG_KEY_SIZE, 256), + Authorization(TAG_AUTH_TIMEOUT, 300), + }; + AuthorizationSet set(params, array_length(params)); + AuthorizationSet set2(set); + EXPECT_EQ(set, set2); +} + +TEST(Construction, NullProvided) { + keymaster_key_param_t params[] = { + Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), + }; + + AuthorizationSet set1(params, 0); + EXPECT_EQ(0U, set1.size()); + EXPECT_EQ(AuthorizationSet::OK, set1.is_valid()); + + AuthorizationSet set2(reinterpret_cast<keymaster_key_param_t*>(NULL), array_length(params)); + EXPECT_EQ(0U, set2.size()); + EXPECT_EQ(AuthorizationSet::OK, set2.is_valid()); +} + +TEST(Lookup, NonRepeated) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD) + .Authorization(TAG_APPLICATION_ID, "my_app", 6) + .Authorization(TAG_KEY_SIZE, 256) + .Authorization(TAG_AUTH_TIMEOUT, 300)); + + EXPECT_EQ(8U, set.size()); + + int pos = set.find(TAG_ALGORITHM); + ASSERT_NE(-1, pos); + EXPECT_EQ(KM_TAG_ALGORITHM, set[pos].tag); + EXPECT_EQ(KM_ALGORITHM_RSA, set[pos].enumerated); + + pos = set.find(TAG_MAC_LENGTH); + EXPECT_EQ(-1, pos); + + uint32_t int_val = 0; + EXPECT_TRUE(set.GetTagValue(TAG_USER_ID, &int_val)); + EXPECT_EQ(7U, int_val); + + keymaster_blob_t blob_val; + EXPECT_TRUE(set.GetTagValue(TAG_APPLICATION_ID, &blob_val)); + EXPECT_EQ(6U, blob_val.data_length); + EXPECT_EQ(0, memcmp(blob_val.data, "my_app", 6)); +} + +TEST(Lookup, Repeated) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_USER_SECURE_ID, 47727) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD) + .Authorization(TAG_APPLICATION_ID, "my_app", 6) + .Authorization(TAG_KEY_SIZE, 256) + .Authorization(TAG_AUTH_TIMEOUT, 300)); + EXPECT_EQ(9U, set.size()); + + int pos = set.find(TAG_PURPOSE); + ASSERT_FALSE(pos == -1); + EXPECT_EQ(KM_TAG_PURPOSE, set[pos].tag); + EXPECT_EQ(KM_PURPOSE_SIGN, set[pos].enumerated); + + pos = set.find(TAG_PURPOSE, pos); + EXPECT_EQ(KM_TAG_PURPOSE, set[pos].tag); + EXPECT_EQ(KM_PURPOSE_VERIFY, set[pos].enumerated); + + EXPECT_EQ(-1, set.find(TAG_PURPOSE, pos)); + + pos = set.find(TAG_USER_SECURE_ID, pos); + EXPECT_EQ(KM_TAG_USER_SECURE_ID, set[pos].tag); + EXPECT_EQ(47727U, set[pos].long_integer); +} + +TEST(Lookup, Indexed) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD) + .Authorization(TAG_APPLICATION_ID, "my_app", 6) + .Authorization(TAG_KEY_SIZE, 256) + .Authorization(TAG_AUTH_TIMEOUT, 300)); + EXPECT_EQ(8U, set.size()); + + EXPECT_EQ(KM_TAG_PURPOSE, set[0].tag); + EXPECT_EQ(KM_PURPOSE_SIGN, set[0].enumerated); + + // Lookup beyond end doesn't work, just returns zeros, but doens't blow up either (verify by + // running under valgrind). + EXPECT_EQ(KM_TAG_INVALID, set[10].tag); +} + +TEST(Serialization, RoundTrip) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD) + .Authorization(TAG_APPLICATION_ID, "my_app", 6) + .Authorization(TAG_KEY_SIZE, 256) + .Authorization(TAG_USER_SECURE_ID, 47727) + .Authorization(TAG_AUTH_TIMEOUT, 300) + .Authorization(TAG_ALL_USERS) + .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3) + .Authorization(TAG_ACTIVE_DATETIME, 10)); + + size_t size = set.SerializedSize(); + EXPECT_TRUE(size > 0); + + UniquePtr<uint8_t[]> buf(new uint8_t[size]); + EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size)); + AuthorizationSet deserialized(buf.get(), size); + + EXPECT_EQ(AuthorizationSet::OK, deserialized.is_valid()); + EXPECT_EQ(set, deserialized); + + int pos = deserialized.find(TAG_APPLICATION_ID); + ASSERT_NE(-1, pos); + EXPECT_EQ(KM_TAG_APPLICATION_ID, deserialized[pos].tag); + EXPECT_EQ(6U, deserialized[pos].blob.data_length); + EXPECT_EQ(0, memcmp(deserialized[pos].blob.data, "my_app", 6)); +} + +TEST(Deserialization, Deserialize) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD) + .Authorization(TAG_APPLICATION_ID, "my_app", 6) + .Authorization(TAG_KEY_SIZE, 256) + .Authorization(TAG_AUTH_TIMEOUT, 300)); + + size_t size = set.SerializedSize(); + EXPECT_TRUE(size > 0); + + UniquePtr<uint8_t[]> buf(new uint8_t[size]); + EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size)); + AuthorizationSet deserialized; + const uint8_t* p = buf.get(); + EXPECT_TRUE(deserialized.Deserialize(&p, p + size)); + EXPECT_EQ(p, buf.get() + size); + + EXPECT_EQ(AuthorizationSet::OK, deserialized.is_valid()); + + EXPECT_EQ(set.size(), deserialized.size()); + for (size_t i = 0; i < set.size(); ++i) { + EXPECT_EQ(set[i].tag, deserialized[i].tag); + } + + int pos = deserialized.find(TAG_APPLICATION_ID); + ASSERT_NE(-1, pos); + EXPECT_EQ(KM_TAG_APPLICATION_ID, deserialized[pos].tag); + EXPECT_EQ(6U, deserialized[pos].blob.data_length); + EXPECT_EQ(0, memcmp(deserialized[pos].blob.data, "my_app", 6)); +} + +TEST(Deserialization, TooShortBuffer) { + uint8_t buf[] = {0, 0, 0}; + AuthorizationSet deserialized(buf, array_length(buf)); + EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid()); + + const uint8_t* p = buf; + EXPECT_FALSE(deserialized.Deserialize(&p, p + array_length(buf))); + EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid()); +} + +TEST(Deserialization, InvalidLengthField) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD) + .Authorization(TAG_APPLICATION_ID, "my_app", 6) + .Authorization(TAG_KEY_SIZE, 256) + .Authorization(TAG_AUTH_TIMEOUT, 300)); + + size_t size = set.SerializedSize(); + EXPECT_TRUE(size > 0); + + UniquePtr<uint8_t[]> buf(new uint8_t[size]); + EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size)); + *reinterpret_cast<uint32_t*>(buf.get()) = 9; + + AuthorizationSet deserialized(buf.get(), size); + EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid()); + + const uint8_t* p = buf.get(); + EXPECT_FALSE(deserialized.Deserialize(&p, p + size)); + EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid()); +} + +static uint32_t read_uint32(const uint8_t* buf) { + uint32_t val; + memcpy(&val, buf, sizeof(val)); + return val; +} + +static void add_to_uint32(uint8_t* buf, int delta) { + uint32_t val; + memcpy(&val, buf, sizeof(val)); + val += delta; + memcpy(buf, &val, sizeof(val)); +} + +TEST(Deserialization, MalformedIndirectData) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_APPLICATION_ID, "my_app", 6) + .Authorization(TAG_APPLICATION_DATA, "foo", 3)); + size_t size = set.SerializedSize(); + + UniquePtr<uint8_t[]> buf(new uint8_t[size]); + EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size)); + + // This sucks. This test, as written, requires intimate knowledge of the serialized layout of + // this particular set, which means it's brittle. But it's important to test that we handle + // broken serialized data and I can't think of a better way to write this. + // + // The contents of buf are: + // + // Bytes: Content: + // 0-3 Length of string data, which is 9. + // 4-9 "my_app" + // 10-12 "foo" + // 13-16 Number of elements, which is 2. + // 17-20 Length of elements, which is 24. + // 21-24 First tag, TAG_APPLICATION_ID + // 25-28 Length of string "my_app", 6 + // 29-32 Offset of string "my_app", 0 + // 33-36 Second tag, TAG_APPLICATION_DATA + // 37-40 Length of string "foo", 3 + // 41-44 Offset of string "foo", 6 + + // Check that stuff is where we think. + EXPECT_EQ('m', buf[4]); + EXPECT_EQ('f', buf[10]); + // Length of "my_app" + EXPECT_EQ(6U, read_uint32(buf.get() + 25)); + // Offset of "my_app" + EXPECT_EQ(0U, read_uint32(buf.get() + 29)); + // Length of "foo" + EXPECT_EQ(3U, read_uint32(buf.get() + 37)); + // Offset of "foo" + EXPECT_EQ(6U, read_uint32(buf.get() + 41)); + + // Check that deserialization works. + AuthorizationSet deserialized1(buf.get(), size); + EXPECT_EQ(AuthorizationSet::OK, deserialized1.is_valid()); + + const uint8_t* p = buf.get(); + EXPECT_TRUE(deserialized1.Deserialize(&p, p + size)); + EXPECT_EQ(AuthorizationSet::OK, deserialized1.is_valid()); + + // + // Now mess them up in various ways: + // + + // Move "foo" offset so offset + length goes off the end + add_to_uint32(buf.get() + 41, 1); + AuthorizationSet deserialized2(buf.get(), size); + EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized2.is_valid()); + add_to_uint32(buf.get() + 41, -1); + + // Shorten the "my_app" length to make a gap between the blobs. + add_to_uint32(buf.get() + 25, -1); + AuthorizationSet deserialized3(buf.get(), size); + EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized3.is_valid()); + add_to_uint32(buf.get() + 25, 1); + + // Extend the "my_app" length to make them overlap, and decrease the "foo" length to keep the + // total length the same. We don't detect this but should. + // TODO(swillden): Detect overlaps and holes that leave total size correct. + add_to_uint32(buf.get() + 25, 1); + add_to_uint32(buf.get() + 37, -1); + AuthorizationSet deserialized4(buf.get(), size); + EXPECT_EQ(AuthorizationSet::OK, deserialized4.is_valid()); +} + +TEST(Growable, SuccessfulRoundTrip) { + AuthorizationSet growable; + EXPECT_TRUE(growable.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA))); + EXPECT_EQ(1U, growable.size()); + + EXPECT_TRUE(growable.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY))); + EXPECT_EQ(2U, growable.size()); + + EXPECT_TRUE(growable.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN))); + EXPECT_EQ(3U, growable.size()); + + EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_ID, "data", 4))); + EXPECT_EQ(4U, growable.size()); + + EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_DATA, "some more data", 14))); + EXPECT_EQ(5U, growable.size()); + + size_t serialize_size = growable.SerializedSize(); + UniquePtr<uint8_t[]> serialized(new uint8_t[serialize_size]); + EXPECT_EQ(serialized.get() + serialize_size, + growable.Serialize(serialized.get(), serialized.get() + serialize_size)); + + AuthorizationSet deserialized(serialized.get(), serialize_size); + EXPECT_EQ(growable, deserialized); +} + +TEST(Growable, InsufficientElemBuf) { + AuthorizationSet growable; + EXPECT_EQ(AuthorizationSet::OK, growable.is_valid()); + + // First insertion fits. + EXPECT_TRUE(growable.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA))); + EXPECT_EQ(1U, growable.size()); + EXPECT_EQ(AuthorizationSet::OK, growable.is_valid()); + + // Second does too. + EXPECT_TRUE(growable.push_back(Authorization(TAG_RSA_PUBLIC_EXPONENT, 3))); + EXPECT_EQ(2U, growable.size()); +} + +TEST(Growable, InsufficientIndirectBuf) { + AuthorizationSet growable; + EXPECT_EQ(AuthorizationSet::OK, growable.is_valid()); + + EXPECT_TRUE(growable.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA))); + EXPECT_EQ(1U, growable.size()); + EXPECT_EQ(AuthorizationSet::OK, growable.is_valid()); + + EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_ID, "1234567890", 10))); + EXPECT_EQ(2U, growable.size()); + EXPECT_EQ(AuthorizationSet::OK, growable.is_valid()); + + EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_DATA, "1", 1))); + EXPECT_EQ(3U, growable.size()); + EXPECT_EQ(AuthorizationSet::OK, growable.is_valid()); + + // Can still add another entry without indirect data. Now it's full. + EXPECT_TRUE(growable.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN))); + EXPECT_EQ(4U, growable.size()); + EXPECT_EQ(AuthorizationSet::OK, growable.is_valid()); +} + +TEST(Growable, PushBackSets) { + AuthorizationSetBuilder builder; + builder.Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD) + .Authorization(TAG_APPLICATION_ID, "my_app", 6) + .Authorization(TAG_KEY_SIZE, 256) + .Authorization(TAG_AUTH_TIMEOUT, 300); + + AuthorizationSet set1(builder.build()); + AuthorizationSet set2(builder.build()); + + AuthorizationSet combined; + EXPECT_TRUE(combined.push_back(set1)); + EXPECT_TRUE(combined.push_back(set2)); + EXPECT_EQ(set1.size() + set2.size(), combined.size()); + EXPECT_EQ(12U, combined.indirect_size()); +} + +TEST(GetValue, GetInt) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD) + .Authorization(TAG_APPLICATION_ID, "my_app", 6) + .Authorization(TAG_AUTH_TIMEOUT, 300)); + + uint32_t val; + EXPECT_TRUE(set.GetTagValue(TAG_USER_ID, &val)); + EXPECT_EQ(7U, val); + + // Find one that isn't there + EXPECT_FALSE(set.GetTagValue(TAG_KEY_SIZE, &val)); +} + +TEST(GetValue, GetLong) { + AuthorizationSet set1(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3)); + + AuthorizationSet set2(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)); + + uint64_t val; + EXPECT_TRUE(set1.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &val)); + EXPECT_EQ(3U, val); + + // Find one that isn't there + EXPECT_FALSE(set2.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &val)); +} + +TEST(GetValue, GetLongRep) { + AuthorizationSet set1(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_SECURE_ID, 8338) + .Authorization(TAG_USER_SECURE_ID, 4334) + .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3)); + + AuthorizationSet set2(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)); + + uint64_t val; + EXPECT_TRUE(set1.GetTagValue(TAG_USER_SECURE_ID, 0, &val)); + EXPECT_EQ(8338U, val); + EXPECT_TRUE(set1.GetTagValue(TAG_USER_SECURE_ID, 1, &val)); + EXPECT_EQ(4334U, val); + + // Find one that isn't there + EXPECT_FALSE(set2.GetTagValue(TAG_USER_SECURE_ID, &val)); +} + +TEST(GetValue, GetEnum) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD) + .Authorization(TAG_APPLICATION_ID, "my_app", 6) + .Authorization(TAG_AUTH_TIMEOUT, 300)); + + keymaster_algorithm_t val; + EXPECT_TRUE(set.GetTagValue(TAG_ALGORITHM, &val)); + EXPECT_EQ(KM_ALGORITHM_RSA, val); + + // Find one that isn't there + keymaster_padding_t val2; + EXPECT_FALSE(set.GetTagValue(TAG_PADDING, &val2)); +} + +TEST(GetValue, GetEnumRep) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD) + .Authorization(TAG_APPLICATION_ID, "my_app", 6) + .Authorization(TAG_AUTH_TIMEOUT, 300)); + + keymaster_purpose_t val; + EXPECT_TRUE(set.GetTagValue(TAG_PURPOSE, 0, &val)); + EXPECT_EQ(KM_PURPOSE_SIGN, val); + EXPECT_TRUE(set.GetTagValue(TAG_PURPOSE, 1, &val)); + EXPECT_EQ(KM_PURPOSE_VERIFY, val); + + // Find one that isn't there + EXPECT_FALSE(set.GetTagValue(TAG_PURPOSE, 2, &val)); +} + +TEST(GetValue, GetDate) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD) + .Authorization(TAG_APPLICATION_ID, "my_app", 6) + .Authorization(TAG_AUTH_TIMEOUT, 300)); + + uint64_t val; + EXPECT_TRUE(set.GetTagValue(TAG_ACTIVE_DATETIME, &val)); + EXPECT_EQ(10U, val); + + // Find one that isn't there + EXPECT_FALSE(set.GetTagValue(TAG_USAGE_EXPIRE_DATETIME, &val)); +} + +TEST(GetValue, GetBlob) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD) + .Authorization(TAG_APPLICATION_ID, "my_app", 6) + .Authorization(TAG_AUTH_TIMEOUT, 300)); + + keymaster_blob_t val; + EXPECT_TRUE(set.GetTagValue(TAG_APPLICATION_ID, &val)); + EXPECT_EQ(6U, val.data_length); + EXPECT_EQ(0, memcmp(val.data, "my_app", 6)); + + // Find one that isn't there + EXPECT_FALSE(set.GetTagValue(TAG_APPLICATION_DATA, &val)); +} + +TEST(Deduplication, NoDuplicates) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)); + AuthorizationSet copy(set); + + EXPECT_EQ(copy, set); + set.Deduplicate(); + EXPECT_EQ(copy.size(), set.size()); + + // Sets no longer compare equal, because of ordering (ugh, maybe it should be + // AuthorizationList, not AuthorizationSet). + EXPECT_NE(copy, set); +} + +TEST(Deduplication, NoDuplicatesHasInvalid) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_INVALID) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)); + AuthorizationSet copy(set); + + EXPECT_EQ(copy, set); + set.Deduplicate(); + + // Deduplicate should have removed the invalid. + EXPECT_EQ(copy.size() - 1, set.size()); + EXPECT_NE(copy, set); +} + +TEST(Deduplication, DuplicateEnum) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)); + AuthorizationSet copy(set); + + EXPECT_EQ(copy, set); + set.Deduplicate(); + EXPECT_EQ(copy.size() - 2, set.size()); + EXPECT_NE(copy, set); +} + +TEST(Deduplication, DuplicateBlob) { + AuthorizationSet set(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_APPLICATION_DATA, "data", 4) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_APPLICATION_DATA, "data", 4) + .Authorization(TAG_APPLICATION_DATA, "foo", 3) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)); + AuthorizationSet copy(set); + + EXPECT_EQ(copy, set); + set.Deduplicate(); + EXPECT_EQ(copy.size() - 3, set.size()); + EXPECT_NE(copy, set); + + // The real test here is that valgrind reports no leak. +} + +TEST(Union, Disjoint) { + AuthorizationSet set1(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_APPLICATION_DATA, "data", 4)); + + AuthorizationSet set2(AuthorizationSetBuilder() + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_APPLICATION_DATA, "foo", 3) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)); + + AuthorizationSet expected(AuthorizationSetBuilder() + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_APPLICATION_DATA, "data", 4) + .Authorization(TAG_APPLICATION_DATA, "foo", 3)); + + set1.Union(set2); + EXPECT_EQ(expected, set1); +} + +TEST(Union, Overlap) { + AuthorizationSet set1(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_APPLICATION_DATA, "data", 4)); + + AuthorizationSet set2(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_APPLICATION_DATA, "data", 4)); + + AuthorizationSet expected(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_APPLICATION_DATA, "data", 4)); + + set1.Union(set2); + EXPECT_EQ(expected, set1); +} + +TEST(Union, Empty) { + AuthorizationSet set1(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_APPLICATION_DATA, "data", 4)); + + AuthorizationSet set2; + + AuthorizationSet expected(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_APPLICATION_DATA, "data", 4)); + + set1.Union(set2); + EXPECT_EQ(expected, set1); +} + +TEST(Difference, Disjoint) { + AuthorizationSet set1(AuthorizationSetBuilder() + .Authorization(TAG_APPLICATION_DATA, "data", 4) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ACTIVE_DATETIME, 10)); + + AuthorizationSet set2(AuthorizationSetBuilder() + .Authorization(TAG_USER_ID, 7) + .Authorization(TAG_APPLICATION_DATA, "foo", 3) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)); + + // Elements are the same as set1, but happen to be in a different order + AuthorizationSet expected(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_APPLICATION_DATA, "data", 4)); + + set1.Difference(set2); + EXPECT_EQ(expected, set1); +} + +TEST(Difference, Overlap) { + AuthorizationSet set1(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_APPLICATION_DATA, "data", 4)); + + AuthorizationSet set2(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_APPLICATION_DATA, "data", 4)); + + AuthorizationSet empty; + set1.Difference(set2); + EXPECT_EQ(empty, set1); + EXPECT_EQ(0U, set1.size()); +} + +TEST(Difference, NullSet) { + AuthorizationSet set1(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_APPLICATION_DATA, "data", 4)); + + AuthorizationSet set2; + + AuthorizationSet expected(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_ACTIVE_DATETIME, 10) + .Authorization(TAG_APPLICATION_DATA, "data", 4)); + + set1.Difference(set2); + EXPECT_EQ(expected, set1); +} + +} // namespace test +} // namespace keymaster diff --git a/unit_test/ecies_kem_test.cpp b/unit_test/ecies_kem_test.cpp new file mode 100644 index 0000000..f653dc0 --- a/dev/null +++ b/unit_test/ecies_kem_test.cpp @@ -0,0 +1,73 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecies_kem.h" + +#include <gtest/gtest.h> +#include <openssl/evp.h> + +#include <hardware/keymaster_defs.h> +#include <keymaster/android_keymaster_utils.h> + +#include "android_keymaster_test_utils.h" +#include "nist_curve_key_exchange.h" + +using std::string; + +namespace keymaster { +namespace test { + +StdoutLogger logger; + +static const keymaster_ec_curve_t kEcCurves[] = {KM_EC_CURVE_P_224, KM_EC_CURVE_P_256, + KM_EC_CURVE_P_384, KM_EC_CURVE_P_521}; + +/** + * TestConsistency just tests that the basic key encapsulation hold. + */ +TEST(EciesKem, TestConsistency) { + static const uint32_t kKeyLen = 32; + for (auto& curve : kEcCurves) { + AuthorizationSet kem_description(AuthorizationSetBuilder() + .Authorization(TAG_EC_CURVE, curve) + .Authorization(TAG_KDF, KM_KDF_RFC5869_SHA256) + .Authorization(TAG_ECIES_SINGLE_HASH_MODE) + .Authorization(TAG_KEY_SIZE, kKeyLen)); + keymaster_error_t error; + EciesKem* kem = new EciesKem(kem_description, &error); + ASSERT_EQ(KM_ERROR_OK, error); + + NistCurveKeyExchange* key_exchange = NistCurveKeyExchange::GenerateKeyExchange(curve); + Buffer peer_public_value; + ASSERT_TRUE(key_exchange->public_value(&peer_public_value)); + + Buffer output_clear_key; + Buffer output_encrypted_key; + ASSERT_TRUE(kem->Encrypt(peer_public_value, &output_clear_key, &output_encrypted_key)); + ASSERT_EQ(kKeyLen, output_clear_key.available_read()); + ASSERT_EQ(peer_public_value.available_read(), output_encrypted_key.available_read()); + + Buffer decrypted_clear_key; + ASSERT_TRUE( + kem->Decrypt(key_exchange->private_key(), output_encrypted_key, &decrypted_clear_key)); + ASSERT_EQ(kKeyLen, decrypted_clear_key.available_read()); + EXPECT_EQ(0, memcmp(output_clear_key.peek_read(), decrypted_clear_key.peek_read(), + output_clear_key.available_read())); + } +} + +} // namespace test +} // namespace keymaster diff --git a/unit_test/gtest_main.cpp b/unit_test/gtest_main.cpp new file mode 100644 index 0000000..6072749 --- a/dev/null +++ b/unit_test/gtest_main.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> + +#include <openssl/engine.h> + +int main(int argc, char** argv) { +#if !defined(OPENSSL_IS_BORINGSSL) + ERR_load_crypto_strings(); +#endif // not OPENSSL_IS_BORINGSSL + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); +#if !defined(OPENSSL_IS_BORINGSSL) + // Clean up stuff OpenSSL leaves around, so Valgrind doesn't complain. + CRYPTO_cleanup_all_ex_data(); + ERR_remove_thread_state(NULL); + ERR_free_strings(); +#endif // not OPENSSL_IS_BORINGSSL + return result; +} diff --git a/unit_test/hkdf_test.cpp b/unit_test/hkdf_test.cpp new file mode 100644 index 0000000..3d3f092 --- a/dev/null +++ b/unit_test/hkdf_test.cpp @@ -0,0 +1,78 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hkdf.h" + +#include <gtest/gtest.h> +#include <string.h> + +#include "android_keymaster_test_utils.h" + +using std::string; + +namespace keymaster { +namespace test { + +struct HkdfTest { + const char* key_hex; + const char* salt_hex; + const char* info_hex; + const char* output_hex; +}; + +// These test cases are taken from +// https://tools.ietf.org/html/rfc5869#appendix-A. +static const HkdfTest kHkdfTests[] = { + { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", + "f0f1f2f3f4f5f6f7f8f9", + "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865", + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c" + "2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f", + "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c" + "8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf", + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdc" + "dddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e" + "590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87", + }, + { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "", "", + "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8", + }, +}; + +TEST(HkdfTest, Hkdf) { + for (auto& test : kHkdfTests) { + const string key = hex2str(test.key_hex); + const string salt = hex2str(test.salt_hex); + const string info = hex2str(test.info_hex); + const string expected = hex2str(test.output_hex); + size_t output_len = expected.size(); + uint8_t output[output_len]; + Rfc5869Sha256Kdf hkdf; + ASSERT_TRUE(hkdf.Init(reinterpret_cast<const uint8_t*>(key.data()), key.size(), + reinterpret_cast<const uint8_t*>(salt.data()), salt.size())); + ASSERT_TRUE(hkdf.GenerateKey(reinterpret_cast<const uint8_t*>(info.data()), info.size(), + output, output_len)); + EXPECT_EQ(0, memcmp(output, expected.data(), output_len)); + } +} + +} // namespace test +} // namespace keymaster diff --git a/unit_test/hmac_test.cpp b/unit_test/hmac_test.cpp new file mode 100644 index 0000000..04f9356 --- a/dev/null +++ b/unit_test/hmac_test.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hmac.h" + +#include <gtest/gtest.h> +#include <string.h> + +#include "android_keymaster_test_utils.h" + +using std::string; + +namespace keymaster { + +namespace test { + +struct HmacTest { + const char* data; + const char* key; + uint8_t digest[32]; +}; + +static const HmacTest kHmacTests[] = { + { + "Test Using Larger Than Block-Size Key - Hash Key First", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + { + 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, + 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, + 0x0e, 0xe3, 0x7f, 0x54, + }, + }, + { + "The test message for the MD2, MD5, and SHA-1 hashing algorithms.", + "46697265666f7820616e64205468756e64657242697264206172652061776573" + "6f6d652100", + { + 0x05, 0x75, 0x9a, 0x9e, 0x70, 0x5e, 0xe7, 0x44, 0xe2, 0x46, 0x4b, 0x92, 0x22, 0x14, + 0x22, 0xe0, 0x1b, 0x92, 0x8a, 0x0c, 0xfe, 0xf5, 0x49, 0xe9, 0xa7, 0x1b, 0x56, 0x7d, + 0x1d, 0x29, 0x40, 0x48, + }, + }, +}; + +TEST(HmacTest, SHA256) { + for (size_t i = 0; i < 2; i++) { + const HmacTest& test(kHmacTests[i]); + + HmacSha256 hmac; + const string key = hex2str(test.key); + Buffer key_buffer(key.data(), key.size()); + ASSERT_TRUE(hmac.Init(key_buffer)); + + uint8_t digest_copy[sizeof(test.digest)]; + memcpy(digest_copy, test.digest, sizeof(test.digest)); + Buffer digest_buffer(reinterpret_cast<uint8_t*>(digest_copy), sizeof(digest_copy)); + + Buffer data_buffer(test.data, strlen(test.data)); + EXPECT_TRUE(hmac.Verify(data_buffer, digest_buffer)); + + digest_copy[16] ^= 0x80; + digest_buffer.Reinitialize(reinterpret_cast<uint8_t*>(digest_copy), sizeof(digest_copy)); + EXPECT_FALSE(hmac.Verify(data_buffer, digest_buffer)); + } +} + +} // namespace test +} // namespace keymaster diff --git a/unit_test/kdf1_test.cpp b/unit_test/kdf1_test.cpp new file mode 100644 index 0000000..9c8b0d5 --- a/dev/null +++ b/unit_test/kdf1_test.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "kdf1.h" +#include <gtest/gtest.h> +#include <string.h> + +#include "android_keymaster_test_utils.h" + +using std::string; + +namespace keymaster { + +namespace test { + +struct Kdf1Test { + const char* key_hex; + const char* expected_output_hex; + keymaster_digest_t digest_type; +}; + +static const Kdf1Test kKdf1Tests[] = { + {"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d764374152e0ac009e509e7ba30cd2f1778" + "e113b64e135cf4e2292c75efe5288edfda4", + "5f8de105b5e96b2e490ddecbd147dd1def7e3b8e0e6a26eb7b956ccb8b3bdc1ca975bc57c3989e8fbad31a224655d" + "800c46954840ff32052cdf0d640562bdfadfa263cfccf3c52b29f2af4a1869959bc77f854cf15bd7a25192985a842" + "dbff8e13efee5b7e7e55bbe4d389647c686a9a9ab3fb889b2d7767d3837eea4e0a2f04", + KM_DIGEST_SHA1}}; + +TEST(Kdf1Test, Kdf1) { + for (auto& test : kKdf1Tests) { + const string key = hex2str(test.key_hex); + const string expected_output = hex2str(test.expected_output_hex); + size_t output_len = expected_output.size(); + uint8_t output[output_len]; + + Kdf1 kdf1; + ASSERT_TRUE( + kdf1.Init(test.digest_type, reinterpret_cast<const uint8_t*>(key.data()), key.size())); + ASSERT_TRUE(kdf1.GenerateKey(nullptr, 0, output, output_len)); + EXPECT_EQ(0, memcmp(output, expected_output.data(), output_len)); + } +} + +} // namespace test + +} // namespace keymaster diff --git a/unit_test/kdf2_test.cpp b/unit_test/kdf2_test.cpp new file mode 100644 index 0000000..29ff40a --- a/dev/null +++ b/unit_test/kdf2_test.cpp @@ -0,0 +1,86 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "kdf2.h" +#include <gtest/gtest.h> +#include <string.h> + +#include "android_keymaster_test_utils.h" + +using std::string; + +namespace keymaster { + +namespace test { + +struct Kdf2Test { + const char* key_hex; + const char* info_hex; + const char* expected_output_hex; + keymaster_digest_t digest_type; +}; + +static const Kdf2Test kKdf2Tests[] = { + {"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d764374152e0ac009e509e7ba30cd2f1778" + "e113b64e135cf4e2292c75efe5288edfda4", + "", + "10a2403db42a8743cb989de86e668d168cbe6046e23ff26f741e87949a3bba1311ac179f819a3d18412e9eb45668f" + "2923c087c1299005f8d5fd42ca257bc93e8fee0c5a0d2a8aa70185401fbbd99379ec76c663e9a29d0b70f3fe261a5" + "9cdc24875a60b4aacb1319fa11c3365a8b79a44669f26fba933d012db213d7e3b16349", + KM_DIGEST_SHA_2_256}, + {"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d764374152e0ac009e509e7ba30cd2f1778" + "e113b64e135cf4e2292c75efe5288edfda4", + "", + "0e6a26eb7b956ccb8b3bdc1ca975bc57c3989e8fbad31a224655d800c46954840ff32052cdf0d640562bdfadfa263" + "cfccf3c52b29f2af4a1869959bc77f854cf15bd7a25192985a842dbff8e13efee5b7e7e55bbe4d389647c686a9a9a" + "b3fb889b2d7767d3837eea4e0a2f04b53ca8f50fb31225c1be2d0126c8c7a4753b0807", + KM_DIGEST_SHA1}, + {"CA7C0F8C3FFA87A96E1B74AC8E6AF594347BB40A", "", "744AB703F5BC082E59185F6D049D2D367DB245C2", + KM_DIGEST_SHA1}, + {"0499B502FC8B5BAFB0F4047E731D1F9FD8CD0D8881", "", + "03C62280C894E103C680B13CD4B4AE740A5EF0C72547292F82DC6B1777F47D63BA9D1EA73" + "2DBF386", + KM_DIGEST_SHA1}, + {"5E10B967A95606853E528F04262AD18A4767C761163971391E17CB05A21668D4CE2B9F151617408042CE091958382" + "3FD346D1751FBE2341AF2EE0461B62F100FFAD4F723F70C18B38238ED183E9398C8CA517EE0CBBEFFF9C59471FE27" + "8093924089480DBC5A38E9A1A97D23038106847D0D22ECF85F49A861821199BAFCB0D74E6ACFFD7D142765EBF4C71" + "2414FE4B6AB957F4CB466B46601289BB82060428272842EE28F113CD11F39431CBFFD823254CE472E2105E49B3D7F" + "113B825076E6264585807BC46454665F27C5E4E1A4BD03470486322981FDC894CCA1E2930987C92C15A38BC42EB38" + "810E867C4432F07259EC00CDBBB0FB99E1727C706DA58DD", + "484D4143204B6579", "BC98EB018CB00EE26D1F97A15AE166912A7AC4C5", KM_DIGEST_SHA1}, + +}; + +TEST(Kdf2Test, Kdf2) { + for (auto& test : kKdf2Tests) { + const string key = hex2str(test.key_hex); + const string info = hex2str(test.info_hex); + const string expected_output = hex2str(test.expected_output_hex); + size_t output_len = expected_output.size(); + uint8_t output[output_len]; + + Kdf2 kdf2; + ASSERT_TRUE( + kdf2.Init(test.digest_type, reinterpret_cast<const uint8_t*>(key.data()), key.size())); + ASSERT_TRUE(kdf2.GenerateKey(reinterpret_cast<const uint8_t*>(info.data()), info.size(), + output, output_len)); + EXPECT_EQ(0, memcmp(output, expected_output.data(), output_len)); + } +} + +} // namespace test + +} // namespace keymaster diff --git a/unit_test/kdf_test.cpp b/unit_test/kdf_test.cpp new file mode 100644 index 0000000..f6f4a93 --- a/dev/null +++ b/unit_test/kdf_test.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "kdf.h" +#include <gtest/gtest.h> + +namespace keymaster { + +namespace test { + +class ForTestAbstractKdf : public Kdf { + bool GenerateKey(const uint8_t* /* info */, size_t /* info_len */, uint8_t* /* output */, + size_t /* output_len */) { + return true; + } +}; + +TEST(KdfTest, Kdf) { + ForTestAbstractKdf kdf; + uint8_t key[128]; + uint8_t salt[128]; + ASSERT_TRUE(kdf.Init(KM_DIGEST_SHA1, key, 128, salt, 128)); + ASSERT_TRUE(kdf.Init(KM_DIGEST_SHA_2_256, key, 128, salt, 128)); + ASSERT_TRUE(kdf.Init(KM_DIGEST_SHA1, key, 128, nullptr, 0)); + ASSERT_FALSE(kdf.Init(KM_DIGEST_MD5, key, 128, salt, 128)); + ASSERT_FALSE(kdf.Init(KM_DIGEST_SHA1, nullptr, 0, salt, 128)); + ASSERT_FALSE(kdf.Init(KM_DIGEST_SHA1, nullptr, 128, salt, 128)); + ASSERT_FALSE(kdf.Init(KM_DIGEST_SHA1, key, 0, salt, 128)); +} + +} // namespace test + +} // namespace keymaster diff --git a/unit_test/key_blob_test.cpp b/unit_test/key_blob_test.cpp new file mode 100644 index 0000000..1e590f0 --- a/dev/null +++ b/unit_test/key_blob_test.cpp @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <algorithm> + +#include <gtest/gtest.h> + +#include <openssl/engine.h> +#include <openssl/rand.h> + +#include <keymaster/authorization_set.h> +#include <keymaster/android_keymaster_utils.h> +#include <keymaster/keymaster_tags.h> + +#include "android_keymaster_test_utils.h" +#include "auth_encrypted_key_blob.h" +#include "integrity_assured_key_blob.h" +#include "ocb_utils.h" + +namespace keymaster { + +namespace test { + +const uint8_t master_key_data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +const uint8_t key_data[5] = {21, 22, 23, 24, 25}; + +class KeyBlobTest : public testing::Test { + protected: + KeyBlobTest() + : master_key_(master_key_data, array_length(master_key_data)), + key_material_(key_data, array_length(key_data)) { + hw_enforced_.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA); + hw_enforced_.push_back(TAG_KEY_SIZE, 256); + hw_enforced_.push_back(TAG_BLOB_USAGE_REQUIREMENTS, KM_BLOB_STANDALONE); + hw_enforced_.push_back(TAG_MIN_SECONDS_BETWEEN_OPS, 10); + hw_enforced_.push_back(TAG_ALL_USERS); + hw_enforced_.push_back(TAG_NO_AUTH_REQUIRED); + hw_enforced_.push_back(TAG_ORIGIN, KM_ORIGIN_GENERATED); + + sw_enforced_.push_back(TAG_ACTIVE_DATETIME, 10); + sw_enforced_.push_back(TAG_ORIGINATION_EXPIRE_DATETIME, 100); + sw_enforced_.push_back(TAG_CREATION_DATETIME, 10); + + hidden_.push_back(TAG_ROOT_OF_TRUST, "foo", 3); + hidden_.push_back(TAG_APPLICATION_ID, "my_app", 6); + + nonce_.reserve(OCB_NONCE_LENGTH); + EXPECT_EQ(1, RAND_bytes(nonce_.peek_write(), OCB_NONCE_LENGTH)); + nonce_.advance_write(OCB_NONCE_LENGTH); + + tag_.reserve(OCB_TAG_LENGTH); + } + + keymaster_error_t Encrypt() { + return OcbEncryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, key_material_, + nonce_, &ciphertext_, &tag_); + } + + keymaster_error_t Decrypt() { + return OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, ciphertext_, nonce_, + tag_, &decrypted_plaintext_); + } + + keymaster_error_t Serialize() { + return SerializeAuthEncryptedBlob(ciphertext_, hw_enforced_, sw_enforced_, nonce_, tag_, + &serialized_blob_); + } + + keymaster_error_t Deserialize() { + return DeserializeAuthEncryptedBlob(serialized_blob_, &ciphertext_, &hw_enforced_, + &sw_enforced_, &nonce_, &tag_); + } + + AuthorizationSet hw_enforced_; + AuthorizationSet sw_enforced_; + AuthorizationSet hidden_; + Buffer nonce_, tag_; + + KeymasterKeyBlob master_key_; + KeymasterKeyBlob key_material_; + KeymasterKeyBlob ciphertext_; + KeymasterKeyBlob decrypted_plaintext_; + KeymasterKeyBlob serialized_blob_; +}; + +TEST_F(KeyBlobTest, EncryptDecrypt) { + ASSERT_EQ(KM_ERROR_OK, Encrypt()); + ASSERT_EQ(KM_ERROR_OK, Serialize()); + + // key_data shouldn't be anywhere in the blob, ciphertext should. + EXPECT_EQ(serialized_blob_.end(), std::search(serialized_blob_.begin(), serialized_blob_.end(), + key_material_.begin(), key_material_.end())); + EXPECT_NE(serialized_blob_.end(), std::search(serialized_blob_.begin(), serialized_blob_.end(), + ciphertext_.begin(), ciphertext_.end())); + + ciphertext_.Clear(); + nonce_.Clear(); + tag_.Clear(); + AuthorizationSet hw2; + AuthorizationSet sw2; + + ASSERT_EQ(KM_ERROR_OK, DeserializeAuthEncryptedBlob(serialized_blob_, &ciphertext_, &hw2, &sw2, + &nonce_, &tag_)); + KeymasterKeyBlob plaintext; + OcbDecryptKey(hw2, sw2, hidden_, master_key_, ciphertext_, nonce_, tag_, &plaintext); + + EXPECT_EQ(hw_enforced_, hw2); + EXPECT_EQ(sw_enforced_, sw2); + + ASSERT_EQ(key_material_.key_material_size, plaintext.key_material_size); + EXPECT_EQ(0, memcmp(plaintext.begin(), key_material_.begin(), plaintext.key_material_size)); +} + +TEST_F(KeyBlobTest, WrongKeyLength) { + ASSERT_EQ(KM_ERROR_OK, Encrypt()); + ASSERT_EQ(KM_ERROR_OK, Serialize()); + + // Modify the key length, shouldn't be able to parse. + serialized_blob_.writable_data()[1 /* version */ + 4 /* nonce len */ + 12 /* nonce */ + 3]++; + + ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Deserialize()); +} + +TEST_F(KeyBlobTest, WrongNonce) { + ASSERT_EQ(KM_ERROR_OK, Encrypt()); + ASSERT_EQ(KM_ERROR_OK, Serialize()); + + // Find the nonce, then modify it. + auto nonce_ptr = + std::search(serialized_blob_.begin(), serialized_blob_.end(), nonce_.begin(), nonce_.end()); + ASSERT_NE(nonce_ptr, serialized_blob_.end()); + EXPECT_EQ(serialized_blob_.end(), + std::search(nonce_ptr + 1, serialized_blob_.end(), nonce_.begin(), nonce_.end())); + (*const_cast<uint8_t*>(nonce_ptr))++; + + // Deserialization shouldn't be affected, but decryption should fail. + ASSERT_EQ(KM_ERROR_OK, Deserialize()); + ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt()); +} + +TEST_F(KeyBlobTest, WrongTag) { + ASSERT_EQ(KM_ERROR_OK, Encrypt()); + ASSERT_EQ(KM_ERROR_OK, Serialize()); + + // Find the tag, them modify it. + auto tag_ptr = + std::search(serialized_blob_.begin(), serialized_blob_.end(), tag_.begin(), tag_.end()); + ASSERT_NE(tag_ptr, serialized_blob_.end()); + EXPECT_EQ(serialized_blob_.end(), + std::search(tag_ptr + 1, serialized_blob_.end(), tag_.begin(), tag_.end())); + (*const_cast<uint8_t*>(tag_ptr))++; + + // Deserialization shouldn't be affected, but decryption should fail. + ASSERT_EQ(KM_ERROR_OK, Deserialize()); + ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt()); +} + +TEST_F(KeyBlobTest, WrongCiphertext) { + ASSERT_EQ(KM_ERROR_OK, Encrypt()); + ASSERT_EQ(KM_ERROR_OK, Serialize()); + + // Find the ciphertext, them modify it. + auto ciphertext_ptr = std::search(serialized_blob_.begin(), serialized_blob_.end(), + ciphertext_.begin(), ciphertext_.end()); + ASSERT_NE(ciphertext_ptr, serialized_blob_.end()); + EXPECT_EQ(serialized_blob_.end(), std::search(ciphertext_ptr + 1, serialized_blob_.end(), + ciphertext_.begin(), ciphertext_.end())); + (*const_cast<uint8_t*>(ciphertext_ptr))++; + + // Deserialization shouldn't be affected, but decryption should fail. + ASSERT_EQ(KM_ERROR_OK, Deserialize()); + ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt()); +} + +TEST_F(KeyBlobTest, WrongMasterKey) { + ASSERT_EQ(KM_ERROR_OK, Encrypt()); + ASSERT_EQ(KM_ERROR_OK, Serialize()); + + uint8_t wrong_master_data[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + KeymasterKeyBlob wrong_master(wrong_master_data, array_length(wrong_master_data)); + + // Decrypting with wrong master key should fail. + ASSERT_EQ(KM_ERROR_OK, Deserialize()); + ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, + OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, wrong_master, ciphertext_, nonce_, + tag_, &decrypted_plaintext_)); +} + +TEST_F(KeyBlobTest, WrongHwEnforced) { + ASSERT_EQ(KM_ERROR_OK, Encrypt()); + ASSERT_EQ(KM_ERROR_OK, Serialize()); + + // Find enforced serialization data and modify it. + size_t hw_enforced_size = hw_enforced_.SerializedSize(); + UniquePtr<uint8_t[]> hw_enforced_data(new uint8_t[hw_enforced_size]); + hw_enforced_.Serialize(hw_enforced_data.get(), hw_enforced_data.get() + hw_enforced_size); + + auto hw_enforced_ptr = + std::search(serialized_blob_.begin(), serialized_blob_.end(), hw_enforced_data.get(), + hw_enforced_data.get() + hw_enforced_size); + ASSERT_NE(serialized_blob_.end(), hw_enforced_ptr); + EXPECT_EQ(serialized_blob_.end(), + std::search(hw_enforced_ptr + 1, serialized_blob_.end(), hw_enforced_data.get(), + hw_enforced_data.get() + hw_enforced_size)); + (*(const_cast<uint8_t*>(hw_enforced_ptr) + hw_enforced_size - 1))++; + + // Deserialization shouldn't be affected, but decryption should fail. + ASSERT_EQ(KM_ERROR_OK, Deserialize()); + ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt()); +} + +TEST_F(KeyBlobTest, WrongSwEnforced) { + ASSERT_EQ(KM_ERROR_OK, Encrypt()); + ASSERT_EQ(KM_ERROR_OK, Serialize()); + + // Find enforced serialization data and modify it. + size_t sw_enforced_size = sw_enforced_.SerializedSize(); + UniquePtr<uint8_t[]> sw_enforced_data(new uint8_t[sw_enforced_size]); + sw_enforced_.Serialize(sw_enforced_data.get(), sw_enforced_data.get() + sw_enforced_size); + + auto sw_enforced_ptr = + std::search(serialized_blob_.begin(), serialized_blob_.end(), sw_enforced_data.get(), + sw_enforced_data.get() + sw_enforced_size); + ASSERT_NE(serialized_blob_.end(), sw_enforced_ptr); + EXPECT_EQ(serialized_blob_.end(), + std::search(sw_enforced_ptr + 1, serialized_blob_.end(), sw_enforced_data.get(), + sw_enforced_data.get() + sw_enforced_size)); + (*(const_cast<uint8_t*>(sw_enforced_ptr) + sw_enforced_size - 1))++; + + // Deserialization shouldn't be affected, but decryption should fail. + ASSERT_EQ(KM_ERROR_OK, Deserialize()); + ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt()); +} + +TEST_F(KeyBlobTest, EmptyHidden) { + ASSERT_EQ(KM_ERROR_OK, Encrypt()); + ASSERT_EQ(KM_ERROR_OK, Serialize()); + + AuthorizationSet wrong_hidden; + + // Deserialization shouldn't be affected, but decryption should fail. + ASSERT_EQ(KM_ERROR_OK, Deserialize()); + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, + OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_, + nonce_, tag_, &decrypted_plaintext_)); +} + +TEST_F(KeyBlobTest, WrongRootOfTrust) { + ASSERT_EQ(KM_ERROR_OK, Encrypt()); + ASSERT_EQ(KM_ERROR_OK, Serialize()); + + AuthorizationSet wrong_hidden; + wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "bar", 2); + wrong_hidden.push_back(TAG_APPLICATION_ID, "my_app", 6); + + // Deserialization shouldn't be affected, but decryption should fail. + ASSERT_EQ(KM_ERROR_OK, Deserialize()); + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, + OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_, + nonce_, tag_, &decrypted_plaintext_)); +} + +TEST_F(KeyBlobTest, WrongAppId) { + ASSERT_EQ(KM_ERROR_OK, Encrypt()); + ASSERT_EQ(KM_ERROR_OK, Serialize()); + + AuthorizationSet wrong_hidden; + wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "foo", 3); + wrong_hidden.push_back(TAG_APPLICATION_ID, "your_app", 7); + + // Deserialization shouldn't be affected, but decryption should fail. + ASSERT_EQ(KM_ERROR_OK, Deserialize()); + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, + OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_, + nonce_, tag_, &decrypted_plaintext_)); +} + +// This test is especially useful when compiled for 32-bit mode and run under valgrind. +TEST_F(KeyBlobTest, FuzzTest) { + time_t now = time(NULL); + std::cout << "Seeding rand() with " << now << " for fuzz test." << std::endl; + srand(now); + + // Fill large buffer with random bytes. + const int kBufSize = 10000; + UniquePtr<uint8_t[]> buf(new uint8_t[kBufSize]); + for (size_t i = 0; i < kBufSize; ++i) + buf[i] = static_cast<uint8_t>(rand()); + + // Try to deserialize every offset with multiple methods. + size_t deserialize_auth_encrypted_success = 0; + for (size_t i = 0; i < kBufSize; ++i) { + keymaster_key_blob_t blob = {buf.get() + i, kBufSize - i}; + KeymasterKeyBlob key_blob(blob); + + // Integrity-assured blob. + ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, + DeserializeIntegrityAssuredBlob(key_blob, hidden_, &key_material_, &hw_enforced_, + &sw_enforced_)); + + // Auth-encrypted OCB blob. + keymaster_error_t error = DeserializeAuthEncryptedBlob( + key_blob, &ciphertext_, &hw_enforced_, &sw_enforced_, &nonce_, &tag_); + if (error == KM_ERROR_OK) { + // It's possible to deserialize successfully. Decryption should always fail. + ++deserialize_auth_encrypted_success; + error = OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, ciphertext_, + nonce_, tag_, &decrypted_plaintext_); + } + ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, error) + << "Somehow sucessfully parsed a blob with seed " << now << " at offset " << i; + } +} + +TEST_F(KeyBlobTest, UnderflowTest) { + uint8_t buf[0]; + keymaster_key_blob_t blob = {buf, 0}; + KeymasterKeyBlob key_blob(blob); + EXPECT_NE(nullptr, key_blob.key_material); + EXPECT_EQ(0U, key_blob.key_material_size); + + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, + DeserializeIntegrityAssuredBlob(key_blob, hidden_, &key_material_, &hw_enforced_, + &sw_enforced_)); + + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, + DeserializeAuthEncryptedBlob(key_blob, &ciphertext_, &hw_enforced_, &sw_enforced_, + &nonce_, &tag_)); +} + +TEST_F(KeyBlobTest, DupBufferToolarge) { + uint8_t buf[0]; + keymaster_key_blob_t blob = {buf, 0}; + blob.key_material_size = 16 * 1024 * 1024 + 1; + KeymasterKeyBlob key_blob(blob); + EXPECT_EQ(nullptr, key_blob.key_material); + EXPECT_EQ(0U, key_blob.key_material_size); + + ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, + DeserializeIntegrityAssuredBlob(key_blob, hidden_, &key_material_, &hw_enforced_, + &sw_enforced_)); + + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, + DeserializeAuthEncryptedBlob(key_blob, &ciphertext_, &hw_enforced_, &sw_enforced_, + &nonce_, &tag_)); +} + +} // namespace test +} // namespace keymaster diff --git a/unit_test/keymaster0_engine.h b/unit_test/keymaster0_engine.h new file mode 100644 index 0000000..aedd85c --- a/dev/null +++ b/unit_test/keymaster0_engine.h @@ -0,0 +1,103 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSTEM_KEYMASTER_KEYMASTER0_ENGINE_H_ +#define SYSTEM_KEYMASTER_KEYMASTER0_ENGINE_H_ + +#include <memory> + +#include <openssl/ec.h> +#include <openssl/engine.h> +#include <openssl/ex_data.h> +#include <openssl/rsa.h> + +#include <hardware/keymaster0.h> +#include <hardware/keymaster_defs.h> + +namespace keymaster { + +struct KeymasterKeyBlob; + +/* Keymaster0Engine is a BoringSSL ENGINE that implements RSA & EC by forwarding the requested + * operations to a keymaster0 module. */ +class Keymaster0Engine { + public: + /** + * Create a Keymaster0Engine, wrapping the provided keymaster0_device. The engine takes + * ownership of the device, and will close it during destruction. + */ + explicit Keymaster0Engine(const keymaster0_device_t* keymaster0_device); + ~Keymaster0Engine(); + + bool supports_ec() const { return supports_ec_; } + + bool GenerateRsaKey(uint64_t public_exponent, uint32_t public_modulus, + KeymasterKeyBlob* key_material) const; + bool GenerateEcKey(uint32_t key_size, KeymasterKeyBlob* key_material) const; + + bool ImportKey(keymaster_key_format_t key_format, const KeymasterKeyBlob& to_import, + KeymasterKeyBlob* imported_key_material) const; + bool DeleteKey(const KeymasterKeyBlob& blob) const; + bool DeleteAllKeys() const; + + RSA* BlobToRsaKey(const KeymasterKeyBlob& blob) const; + EC_KEY* BlobToEcKey(const KeymasterKeyBlob& blob) const; + + const keymaster_key_blob_t* RsaKeyToBlob(const RSA* rsa) const; + const keymaster_key_blob_t* EcKeyToBlob(const EC_KEY* rsa) const; + + const keymaster0_device_t* device() { return keymaster0_device_; } + + EVP_PKEY* GetKeymaster0PublicKey(const KeymasterKeyBlob& blob) const; + + private: + Keymaster0Engine(const Keymaster0Engine&); // Uncopyable + void operator=(const Keymaster0Engine&); // Unassignable + + static int keyblob_dup(CRYPTO_EX_DATA* to, const CRYPTO_EX_DATA* from, void** from_d, int index, + long argl, void* argp); + static void keyblob_free(void* parent, void* ptr, CRYPTO_EX_DATA* data, int index, long argl, + void* argp); + static int rsa_private_transform(RSA* rsa, uint8_t* out, const uint8_t* in, size_t len); + static int ecdsa_sign(const uint8_t* digest, size_t digest_len, uint8_t* sig, + unsigned int* sig_len, EC_KEY* ec_key); + + struct Malloc_Delete { + void operator()(void* p) { free(p); } + }; + + bool Keymaster0Sign(const void* signing_params, const keymaster_key_blob_t& key_blob, + const uint8_t* data, const size_t data_length, + std::unique_ptr<uint8_t[], Malloc_Delete>* signature, + size_t* signature_length) const; + + int RsaPrivateTransform(RSA* rsa, uint8_t* out, const uint8_t* in, size_t len) const; + int EcdsaSign(const uint8_t* digest, size_t digest_len, uint8_t* sig, unsigned int* sig_len, + EC_KEY* ec_key) const; + + const keymaster0_device_t* keymaster0_device_; + ENGINE* const engine_; + int rsa_index_, ec_key_index_; + bool supports_ec_; + RSA_METHOD rsa_method_; + ECDSA_METHOD ecdsa_method_; + + static Keymaster0Engine* instance_; +}; + +} // namespace keymaster + +#endif // SYSTEM_KEYMASTER_KEYMASTER0_ENGINE_H_ diff --git a/unit_test/keymaster1_engine.h b/unit_test/keymaster1_engine.h new file mode 100644 index 0000000..9e2f13e --- a/dev/null +++ b/unit_test/keymaster1_engine.h @@ -0,0 +1,123 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSTEM_KEYMASTER_KEYMASTER1_ENGINE_H_ +#define SYSTEM_KEYMASTER_KEYMASTER1_ENGINE_H_ + +#include <memory> + +#include <openssl/ec.h> +#include <openssl/engine.h> +#include <openssl/ex_data.h> +#include <openssl/rsa.h> + +#include <hardware/keymaster1.h> +#include <hardware/keymaster_defs.h> + +#include <keymaster/android_keymaster_utils.h> +#include <keymaster/authorization_set.h> + +#include "openssl_utils.h" + +namespace keymaster { + +class Keymaster1Engine { + public: + /** + * Create a Keymaster1Engine, wrapping the provided keymaster1_device. The engine takes + * ownership of the device, and will close it during destruction. + */ + explicit Keymaster1Engine(const keymaster1_device_t* keymaster1_device); + ~Keymaster1Engine(); + + keymaster_error_t GenerateKey(const AuthorizationSet& key_description, + KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced, + AuthorizationSet* sw_enforced) const; + + keymaster_error_t ImportKey(const AuthorizationSet& key_description, + keymaster_key_format_t input_key_material_format, + const KeymasterKeyBlob& input_key_material, + KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced, + AuthorizationSet* sw_enforced) const; + keymaster_error_t DeleteKey(const KeymasterKeyBlob& blob) const; + keymaster_error_t DeleteAllKeys() const; + + struct KeyData { + KeyData(const KeymasterKeyBlob& blob, const AuthorizationSet& params) + : op_handle(0), begin_params(params), key_material(blob), error(KM_ERROR_OK), + expected_openssl_padding(-1) {} + + keymaster_operation_handle_t op_handle; + AuthorizationSet begin_params; + AuthorizationSet finish_params; + KeymasterKeyBlob key_material; + keymaster_error_t error; + int expected_openssl_padding; + }; + + RSA* BuildRsaKey(const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params, + keymaster_error_t* error) const; + EC_KEY* BuildEcKey(const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params, + keymaster_error_t* error) const; + + KeyData* GetData(EVP_PKEY* key) const; + KeyData* GetData(const RSA* rsa) const; + KeyData* GetData(const EC_KEY* rsa) const; + + const keymaster1_device_t* device() const { return keymaster1_device_; } + + EVP_PKEY* GetKeymaster1PublicKey(const KeymasterKeyBlob& blob, + const AuthorizationSet& additional_params, + keymaster_error_t* error) const; + + private: + Keymaster1Engine(const Keymaster1Engine&); // Uncopyable + void operator=(const Keymaster1Engine&); // Unassignable + + RSA_METHOD BuildRsaMethod(); + ECDSA_METHOD BuildEcdsaMethod(); + void ConfigureEngineForRsa(); + void ConfigureEngineForEcdsa(); + + keymaster_error_t Keymaster1Finish(const KeyData* key_data, const keymaster_blob_t& input, + keymaster_blob_t* output); + + static int duplicate_key_data(CRYPTO_EX_DATA* to, const CRYPTO_EX_DATA* from, void** from_d, + int index, long argl, void* argp); + static void free_key_data(void* parent, void* ptr, CRYPTO_EX_DATA* data, int index, long argl, + void* argp); + + static int rsa_sign_raw(RSA* rsa, size_t* out_len, uint8_t* out, size_t max_out, + const uint8_t* in, size_t in_len, int padding); + static int rsa_decrypt(RSA* rsa, size_t* out_len, uint8_t* out, size_t max_out, + const uint8_t* in, size_t in_len, int padding); + static int ecdsa_sign(const uint8_t* digest, size_t digest_len, uint8_t* sig, + unsigned int* sig_len, EC_KEY* ec_key); + + const keymaster1_device_t* const keymaster1_device_; + const std::unique_ptr<ENGINE, ENGINE_Delete> engine_; + const int rsa_index_; + const int ec_key_index_; + + const RSA_METHOD rsa_method_; + const ECDSA_METHOD ecdsa_method_; + + static Keymaster1Engine* instance_; +}; + +} // namespace keymaster + +#endif // SYSTEM_KEYMASTER_KEYMASTER1_ENGINE_H_ diff --git a/unit_test/keymaster_configuration_test.cpp b/unit_test/keymaster_configuration_test.cpp new file mode 100644 index 0000000..81e9598 --- a/dev/null +++ b/unit_test/keymaster_configuration_test.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> + +#include <keymaster/keymaster_configuration.h> + +#ifdef HOST_BUILD +extern "C" { +int __android_log_print(int prio, const char* tag, const char* fmt); +int __android_log_print(int prio, const char* tag, const char* fmt) { + (void)prio, (void)tag, (void)fmt; + std::cout << fmt << std::endl; + return 0; +} +} // extern "C" +#endif // HOST_BUILD + +namespace keymaster { +namespace test { + +TEST(VersionParsingTest, Full) { + EXPECT_EQ(612334U, GetOsVersion("61.23.34")); + EXPECT_EQ(680000U, GetOsVersion("681.23.24")); + EXPECT_EQ(682300U, GetOsVersion("68.231.24")); + EXPECT_EQ(682324U, GetOsVersion("68.23.241")); + EXPECT_EQ(60102U, GetOsVersion("6.1.2-extrajunk")); + EXPECT_EQ(0U, GetOsVersion("extra6.1.2")); +} + +TEST(VersionParsingTest, FullWithExtraChars) {} + +TEST(VersionParsingTest, MajorOnly) { + EXPECT_EQ(60000U, GetOsVersion("6")); + EXPECT_EQ(680000U, GetOsVersion("68")); + EXPECT_EQ(680000U, GetOsVersion("681")); + EXPECT_EQ(60000U, GetOsVersion("6.junk")); +} + +TEST(VersionParsingTest, MajorMinorOnly) { + EXPECT_EQ(60100U, GetOsVersion("6.1")); + EXPECT_EQ(60100U, GetOsVersion("6.1junk")); +} + +TEST(PatchLevelParsingTest, Full) { + EXPECT_EQ(201603U, GetOsPatchlevel("2016-03-23")); + EXPECT_EQ(0U, GetOsPatchlevel("2016-13-23")); + EXPECT_EQ(0U, GetOsPatchlevel("2016-03")); + EXPECT_EQ(0U, GetOsPatchlevel("2016-3-23")); + EXPECT_EQ(0U, GetOsPatchlevel("2016-03-23r")); + EXPECT_EQ(0U, GetOsPatchlevel("r2016-03-23")); +} + +} // namespace test +} // namespace keymaster diff --git a/unit_test/keymaster_enforcement_test.cpp b/unit_test/keymaster_enforcement_test.cpp new file mode 100644 index 0000000..3874744 --- a/dev/null +++ b/unit_test/keymaster_enforcement_test.cpp @@ -0,0 +1,872 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <errno.h> +#include <stdio.h> +#include <time.h> + +#include <keymaster/android_keymaster.h> +#include <keymaster/authorization_set.h> +#include <keymaster/keymaster_enforcement.h> + +#include "android_keymaster_test_utils.h" + +namespace keymaster { +namespace test { + +class TestKeymasterEnforcement : public KeymasterEnforcement { + public: + TestKeymasterEnforcement() + : KeymasterEnforcement(3, 3), current_time_(10000), report_token_valid_(true) {} + + keymaster_error_t AuthorizeOperation(const keymaster_purpose_t purpose, const km_id_t keyid, + const AuthorizationSet& auth_set) { + AuthorizationSet empty_set; + return KeymasterEnforcement::AuthorizeOperation( + purpose, keyid, auth_set, empty_set, 0 /* op_handle */, true /* is_begin_operation */); + } + using KeymasterEnforcement::AuthorizeOperation; + + uint32_t get_current_time() const override { return current_time_; } + bool activation_date_valid(uint64_t activation_date) const override { + // Convert java date to time_t, non-portably. + time_t activation_time = activation_date / 1000; + return difftime(time(NULL), activation_time) >= 0; + } + bool expiration_date_passed(uint64_t expiration_date) const override { + // Convert jave date to time_t, non-portably. + time_t expiration_time = expiration_date / 1000; + return difftime(time(NULL), expiration_time) > 0; + } + bool auth_token_timed_out(const hw_auth_token_t& token, uint32_t timeout) const { + return current_time_ > ntoh(token.timestamp) + timeout; + } + bool ValidateTokenSignature(const hw_auth_token_t&) const override { + return report_token_valid_; + } + + void tick(unsigned seconds = 1) { current_time_ += seconds; } + uint32_t current_time() { return current_time_; } + void set_report_token_valid(bool report_token_valid) { + report_token_valid_ = report_token_valid; + } + + private: + uint32_t current_time_; + bool report_token_valid_; +}; + +class KeymasterBaseTest : public ::testing::Test { + protected: + KeymasterBaseTest() { + past_time = 0; + + time_t t = time(NULL); + future_tm = localtime(&t); + future_tm->tm_year += 1; + future_time = static_cast<uint64_t>(mktime(future_tm)) * 1000; + sign_param = Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN); + } + virtual ~KeymasterBaseTest() {} + + TestKeymasterEnforcement kmen; + + tm past_tm; + tm* future_tm; + uint64_t past_time; + uint64_t future_time; + static const km_id_t key_id = 0xa; + static const uid_t uid = 0xf; + keymaster_key_param_t sign_param; +}; + +TEST_F(KeymasterBaseTest, TestValidKeyPeriodNoTags) { + keymaster_key_param_t params[] = { + sign_param, + }; + AuthorizationSet single_auth_set(params, array_length(params)); + + keymaster_error_t kmer = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, single_auth_set); + ASSERT_EQ(KM_ERROR_OK, kmer); +} + +TEST_F(KeymasterBaseTest, TestInvalidActiveTime) { + keymaster_key_param_t params[] = { + Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), + Authorization(TAG_NO_AUTH_REQUIRED), Authorization(TAG_ACTIVE_DATETIME, future_time), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + ASSERT_EQ(KM_ERROR_KEY_NOT_YET_VALID, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set)); + + // Pubkey ops allowed. + ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set)); +} + +TEST_F(KeymasterBaseTest, TestValidActiveTime) { + keymaster_key_param_t params[] = { + Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ACTIVE_DATETIME, past_time), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + keymaster_error_t kmer_valid_time = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set); + ASSERT_EQ(KM_ERROR_OK, kmer_valid_time); +} + +TEST_F(KeymasterBaseTest, TestInvalidOriginationExpireTime) { + keymaster_key_param_t params[] = { + Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), + Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, past_time), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + ASSERT_EQ(KM_ERROR_KEY_EXPIRED, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set)); + + // Pubkey ops allowed. + ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set)); +} + +TEST_F(KeymasterBaseTest, TestInvalidOriginationExpireTimeOnUsgae) { + keymaster_key_param_t params[] = { + Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), + Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, past_time), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + keymaster_error_t kmer_invalid_origination = + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set); + ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination); +} + +TEST_F(KeymasterBaseTest, TestValidOriginationExpireTime) { + keymaster_key_param_t params[] = { + Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), + Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, future_time), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + keymaster_error_t kmer_valid_origination = + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set); + ASSERT_EQ(KM_ERROR_OK, kmer_valid_origination); +} + +TEST_F(KeymasterBaseTest, TestInvalidUsageExpireTime) { + keymaster_key_param_t params[] = { + Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES), + Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), + Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + keymaster_error_t kmer_invalid_origination = + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set); + ASSERT_EQ(KM_ERROR_KEY_EXPIRED, kmer_invalid_origination); +} + +TEST_F(KeymasterBaseTest, TestInvalidPubkeyUsageExpireTime) { + keymaster_key_param_t params[] = { + Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), + Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), + Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + keymaster_error_t kmer_invalid_origination = + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set); + // Pubkey ops allowed. + ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination); +} + +TEST_F(KeymasterBaseTest, TestInvalidUsageExpireTimeOnOrigination) { + keymaster_key_param_t params[] = { + Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), + Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + keymaster_error_t kmer_invalid_origination = + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set); + ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination); +} + +TEST_F(KeymasterBaseTest, TestValidUsageExpireTime) { + keymaster_key_param_t params[] = { + Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), + Authorization(TAG_USAGE_EXPIRE_DATETIME, future_time), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + keymaster_error_t kmer_valid_usage = + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set); + ASSERT_EQ(KM_ERROR_OK, kmer_valid_usage); +} + +TEST_F(KeymasterBaseTest, TestValidSingleUseAccesses) { + keymaster_key_param_t params[] = { + Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + keymaster_error_t kmer1 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set); + keymaster_error_t kmer2 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set); + + ASSERT_EQ(KM_ERROR_OK, kmer1); + ASSERT_EQ(KM_ERROR_OK, kmer2); +} + +TEST_F(KeymasterBaseTest, TestInvalidMaxOps) { + keymaster_key_param_t params[] = { + Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), + Authorization(TAG_MAX_USES_PER_BOOT, 4), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set)); + ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set)); + ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set)); + ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set)); + ASSERT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set)); + // Pubkey ops allowed. + ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set)); +} + +TEST_F(KeymasterBaseTest, TestOverFlowMaxOpsTable) { + keymaster_key_param_t params[] = { + Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), + Authorization(TAG_MAX_USES_PER_BOOT, 2), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set)); + + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 2 /* key_id */, auth_set)); + + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 3 /* key_id */, auth_set)); + + // Key 4 should fail, because table is full. + EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 4 /* key_id */, auth_set)); + + // Key 1 still works, because it's already in the table and hasn't reached max. + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set)); + + // Key 1 no longer works, because it's reached max. + EXPECT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set)); + + // Key 4 should fail, because table is (still and forever) full. + EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 4 /* key_id */, auth_set)); + + // Pubkey ops allowed. + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set)); + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set)); +} + +TEST_F(KeymasterBaseTest, TestInvalidTimeBetweenOps) { + keymaster_key_param_t params[] = { + Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), + Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 10), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + keymaster_error_t kmer1 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set); + keymaster_error_t kmer2 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set); + keymaster_error_t kmer3 = kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set); + + ASSERT_EQ(KM_ERROR_OK, kmer1); + kmen.tick(2); + ASSERT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, kmer2); + + // Allowed because it's a pubkey op. + ASSERT_EQ(KM_ERROR_OK, kmer3); +} + +TEST_F(KeymasterBaseTest, TestValidTimeBetweenOps) { + keymaster_key_param_t params[] = { + Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), + Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 2), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set)); + kmen.tick(); + EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set)); + kmen.tick(); + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set)); +} + +TEST_F(KeymasterBaseTest, TestOptTimeoutTableOverflow) { + keymaster_key_param_t params[] = { + Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES), + Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 4), + Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set)); + + kmen.tick(); + + // Key 1 fails because it's too soon + EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set)); + + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set)); + + kmen.tick(); + + // Key 1 fails because it's too soon + EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set)); + // Key 2 fails because it's too soon + EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set)); + + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set)); + + kmen.tick(); + + // Key 1 fails because it's too soon + EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set)); + // Key 2 fails because it's too soon + EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set)); + // Key 3 fails because it's too soon + EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set)); + // Key 4 fails because the table is full + EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set)); + + kmen.tick(); + + // Key 4 succeeds because key 1 expired. + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set)); + + // Key 1 fails because the table is full... and key 1 is no longer in it. + EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set)); + // Key 2 fails because it's too soon + EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set)); + // Key 3 fails because it's too soon + EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set)); + + kmen.tick(); + + // Key 1 succeeds because key 2 expired + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set)); + // Key 2 fails because the table is full... and key 2 is no longer in it. + EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set)); + // Key 3 fails because it's too soon + EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set)); + // Key 4 fails because it's too soon + EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set)); + + kmen.tick(4); + + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set)); + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set)); + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set)); +} + +TEST_F(KeymasterBaseTest, TestPubkeyOptTimeoutTableOverflow) { + keymaster_key_param_t params[] = { + Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), + Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 4), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), + }; + + AuthorizationSet auth_set(params, array_length(params)); + + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set)); + + kmen.tick(); + + // Key 1 fails because it's too soon + EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set)); + // Too soo, but pubkey ops allowed. + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set)); +} + +TEST_F(KeymasterBaseTest, TestInvalidPurpose) { + keymaster_purpose_t invalidPurpose1 = static_cast<keymaster_purpose_t>(-1); + keymaster_purpose_t invalidPurpose2 = static_cast<keymaster_purpose_t>(4); + + AuthorizationSet auth_set( + AuthorizationSetBuilder().Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)); + + EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, + kmen.AuthorizeOperation(invalidPurpose1, key_id, auth_set)); + EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, + kmen.AuthorizeOperation(invalidPurpose2, key_id, auth_set)); +} + +TEST_F(KeymasterBaseTest, TestIncompatiblePurposeSymmetricKey) { + AuthorizationSet auth_set(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set)); + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set)); + + EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, + kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, auth_set)); + EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, + kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, auth_set)); +} + +TEST_F(KeymasterBaseTest, TestIncompatiblePurposeAssymmetricKey) { + AuthorizationSet auth_set(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set)); + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set)); + + // This one is allowed because it's a pubkey op. + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, auth_set)); + EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, + kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, auth_set)); +} + +TEST_F(KeymasterBaseTest, TestInvalidCallerNonce) { + AuthorizationSet no_caller_nonce(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT) + .Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES)); + AuthorizationSet caller_nonce(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT) + .Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_HMAC) + .Authorization(TAG_CALLER_NONCE)); + AuthorizationSet begin_params(AuthorizationSetBuilder().Authorization(TAG_NONCE, "foo", 3)); + + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, caller_nonce, begin_params, + 0 /* challenge */, true /* is_begin_operation */)); + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, caller_nonce, begin_params, + 0 /* challenge */, true /* is_begin_operation */)); + EXPECT_EQ(KM_ERROR_CALLER_NONCE_PROHIBITED, + kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, no_caller_nonce, begin_params, + 0 /* challenge */, true /* is_begin_operation */)); + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, no_caller_nonce, begin_params, + 0 /* challenge */, true /* is_begin_operation */)); +} + +TEST_F(KeymasterBaseTest, TestBootloaderOnly) { + AuthorizationSet auth_set(AuthorizationSetBuilder() + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_BOOTLOADER_ONLY)); + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set)); + + // Pubkey ops allowed. + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set)); +} + +TEST_F(KeymasterBaseTest, TestInvalidTag) { + AuthorizationSet auth_set(AuthorizationSetBuilder() + .Authorization(TAG_INVALID) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set)); +} + +TEST_F(KeymasterBaseTest, TestAuthPerOpSuccess) { + hw_auth_token_t token; + memset(&token, 0, sizeof(token)); + token.version = HW_AUTH_TOKEN_VERSION; + token.challenge = 99; + token.user_id = 9; + token.authenticator_id = 0; + token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); + token.timestamp = 0; + + AuthorizationSet auth_set(AuthorizationSetBuilder() + .Authorization(TAG_USER_SECURE_ID, token.user_id) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + AuthorizationSet op_params; + op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); + + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge, + false /* is_begin_operation */)); +} + +TEST_F(KeymasterBaseTest, TestAuthPerOpInvalidTokenSignature) { + hw_auth_token_t token; + memset(&token, 0, sizeof(token)); + token.version = HW_AUTH_TOKEN_VERSION; + token.challenge = 99; + token.user_id = 9; + token.authenticator_id = 0; + token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); + token.timestamp = 0; + + AuthorizationSet auth_set(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC) + .Authorization(TAG_USER_SECURE_ID, token.user_id) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + AuthorizationSet op_params; + op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); + + kmen.set_report_token_valid(false); + EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge, + false /* is_begin_operation */)); + // Pubkey ops allowed. + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params, + token.challenge, false /* is_begin_operation */)); +} + +TEST_F(KeymasterBaseTest, TestAuthPerOpWrongChallenge) { + hw_auth_token_t token; + memset(&token, 0, sizeof(token)); + token.version = HW_AUTH_TOKEN_VERSION; + token.challenge = 99; + token.user_id = 9; + token.authenticator_id = 0; + token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); + token.timestamp = 0; + + AuthorizationSet auth_set(AuthorizationSetBuilder() + .Authorization(TAG_USER_SECURE_ID, token.user_id) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + AuthorizationSet op_params; + op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); + + EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, + token.challenge + 1 /* doesn't match token */, + false /* is_begin_operation */)); +} + +TEST_F(KeymasterBaseTest, TestAuthPerOpNoAuthType) { + hw_auth_token_t token; + memset(&token, 0, sizeof(token)); + token.version = HW_AUTH_TOKEN_VERSION; + token.challenge = 99; + token.user_id = 9; + token.authenticator_id = 0; + token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); + token.timestamp = 0; + + AuthorizationSet auth_set(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_SECURE_ID, token.user_id) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + AuthorizationSet op_params; + op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); + + EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge, + false /* is_begin_operation */)); + // Pubkey ops allowed. + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params, + token.challenge, false /* is_begin_operation */)); +} + +TEST_F(KeymasterBaseTest, TestAuthPerOpWrongAuthType) { + hw_auth_token_t token; + memset(&token, 0, sizeof(token)); + token.version = HW_AUTH_TOKEN_VERSION; + token.challenge = 99; + token.user_id = 9; + token.authenticator_id = 0; + token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); + token.timestamp = 0; + + AuthorizationSet auth_set( + AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_SECURE_ID, token.user_id) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_FINGERPRINT /* doesn't match token */) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + AuthorizationSet op_params; + op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); + + EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge, + false /* is_begin_operation */)); + // Pubkey ops allowed. + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params, + token.challenge, false /* is_begin_operation */)); +} + +TEST_F(KeymasterBaseTest, TestAuthPerOpWrongSid) { + hw_auth_token_t token; + memset(&token, 0, sizeof(token)); + token.version = HW_AUTH_TOKEN_VERSION; + token.challenge = 99; + token.user_id = 9; + token.authenticator_id = 0; + token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); + token.timestamp = 0; + + AuthorizationSet auth_set( + AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_SECURE_ID, token.user_id + 1 /* doesn't match token */) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + AuthorizationSet op_params; + op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); + + EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge, + false /* is_begin_operation */)); + // Pubkey op allowed. + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params, + token.challenge, false /* is_begin_operation */)); +} + +TEST_F(KeymasterBaseTest, TestAuthPerOpSuccessAlternateSid) { + hw_auth_token_t token; + memset(&token, 0, sizeof(token)); + token.version = HW_AUTH_TOKEN_VERSION; + token.challenge = 99; + token.user_id = 9; + token.authenticator_id = 10; + token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); + token.timestamp = 0; + + AuthorizationSet auth_set(AuthorizationSetBuilder() + .Authorization(TAG_USER_SECURE_ID, token.authenticator_id) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + AuthorizationSet op_params; + op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); + + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge, + false /* is_begin_operation */)); +} + +TEST_F(KeymasterBaseTest, TestAuthPerOpMissingToken) { + hw_auth_token_t token; + memset(&token, 0, sizeof(token)); + token.version = HW_AUTH_TOKEN_VERSION; + token.challenge = 99; + token.user_id = 9; + token.authenticator_id = 0; + token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); + token.timestamp = 0; + + AuthorizationSet auth_set(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_SECURE_ID, token.user_id) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + AuthorizationSet op_params; + + // During begin we can skip the auth token + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, + token.challenge, true /* is_begin_operation */)); + // Afterwards we must have authentication + EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge, + false /* is_begin_operation */)); + // Pubkey ops allowed + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params, + token.challenge, false /* is_begin_operation */)); + + auth_set.Reinitialize(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES) + .Authorization(TAG_USER_SECURE_ID, token.user_id) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN) + .build()); + + EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params, + token.challenge, false /* is_begin_operation */)); +} + +TEST_F(KeymasterBaseTest, TestAuthAndNoAuth) { + AuthorizationSet auth_set(AuthorizationSetBuilder() + .Authorization(TAG_USER_SECURE_ID, 1) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set)); +} + +TEST_F(KeymasterBaseTest, TestTimedAuthSuccess) { + hw_auth_token_t token; + memset(&token, 0, sizeof(token)); + token.version = HW_AUTH_TOKEN_VERSION; + token.challenge = 99; + token.user_id = 9; + token.authenticator_id = 0; + token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); + token.timestamp = hton(kmen.current_time()); + + AuthorizationSet auth_set(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_SECURE_ID, token.user_id) + .Authorization(TAG_AUTH_TIMEOUT, 1) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + AuthorizationSet op_params; + op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); + + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, + 0 /* irrelevant */, false /* is_begin_operation */)); +} + +TEST_F(KeymasterBaseTest, TestTimedAuthTimedOut) { + hw_auth_token_t token; + memset(&token, 0, sizeof(token)); + token.version = HW_AUTH_TOKEN_VERSION; + token.challenge = 99; + token.user_id = 9; + token.authenticator_id = 0; + token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); + token.timestamp = hton(static_cast<uint64_t>(kmen.current_time())); + + AuthorizationSet auth_set(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_SECURE_ID, token.user_id) + .Authorization(TAG_AUTH_TIMEOUT, 1) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + AuthorizationSet op_params; + op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token))); + + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, + 0 /* irrelevant */, false /* is_begin_operation */)); + + kmen.tick(1); + + // token still good + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, + 0 /* irrelevant */, false /* is_begin_operation */)); + + kmen.tick(1); + + // token expired, not allowed during begin. + EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, + 0 /* irrelevant */, true /* is_begin_operation */)); + + // token expired, afterwards it's okay. + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, + 0 /* irrelevant */, false /* is_begin_operation */)); + + // Pubkey ops allowed. + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params, + 0 /* irrelevant */, true /* is_begin_operation */)); +} + +TEST_F(KeymasterBaseTest, TestTimedAuthMissingToken) { + hw_auth_token_t token; + memset(&token, 0, sizeof(token)); + token.version = HW_AUTH_TOKEN_VERSION; + token.challenge = 99; + token.user_id = 9; + token.authenticator_id = 0; + token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); + token.timestamp = hton(static_cast<uint64_t>(kmen.current_time())); + + AuthorizationSet auth_set(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_USER_SECURE_ID, token.user_id) + .Authorization(TAG_AUTH_TIMEOUT, 1) + .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY) + .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)); + + AuthorizationSet op_params; + + // Unlike auth-per-op, must have the auth token during begin. + EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge, + true /* is_begin_operation */)); + + // Later we don't check (though begin would fail, so there wouldn't be a later). + EXPECT_EQ(KM_ERROR_OK, + kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge, + false /* is_begin_operation */)); + + // Pubkey ops allowed. + EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params, + token.challenge, true /* is_begin_operation */)); +} + +TEST_F(KeymasterBaseTest, TestCreateKeyId) { + keymaster_key_blob_t blob = {reinterpret_cast<const uint8_t*>("foobar"), 6}; + + km_id_t key_id = 0; + EXPECT_TRUE(KeymasterEnforcement::CreateKeyId(blob, &key_id)); + EXPECT_NE(0U, key_id); +} + +}; /* namespace test */ +}; /* namespace keymaster */ diff --git a/unit_test/keymaster_tags.cpp b/unit_test/keymaster_tags.cpp new file mode 100644 index 0000000..238bc33 --- a/dev/null +++ b/unit_test/keymaster_tags.cpp @@ -0,0 +1,173 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <keymaster/keymaster_tags.h> + +namespace keymaster { + +#ifdef KEYMASTER_NAME_TAGS +const char* StringifyTag(keymaster_tag_t tag) { + switch (tag) { + case KM_TAG_INVALID: + return "KM_TAG_INVALID"; + case KM_TAG_PURPOSE: + return "KM_TAG_PURPOSE"; + case KM_TAG_ALGORITHM: + return "KM_TAG_ALGORITHM"; + case KM_TAG_KEY_SIZE: + return "KM_TAG_KEY_SIZE"; + case KM_TAG_BLOCK_MODE: + return "KM_TAG_BLOCK_MODE"; + case KM_TAG_DIGEST: + return "KM_TAG_DIGEST"; + case KM_TAG_PADDING: + return "KM_TAG_PADDING"; + case KM_TAG_CALLER_NONCE: + return "KM_TAG_CALLER_NONCE"; + case KM_TAG_MIN_MAC_LENGTH: + return "KM_TAG_MIN_MAC_LENGTH"; + case KM_TAG_RSA_PUBLIC_EXPONENT: + return "KM_TAG_RSA_PUBLIC_EXPONENT"; + case KM_TAG_BLOB_USAGE_REQUIREMENTS: + return "KM_TAG_BLOB_USAGE_REQUIREMENTS"; + case KM_TAG_BOOTLOADER_ONLY: + return "KM_TAG_BOOTLOADER_ONLY"; + case KM_TAG_ACTIVE_DATETIME: + return "KM_TAG_ACTIVE_DATETIME"; + case KM_TAG_ORIGINATION_EXPIRE_DATETIME: + return "KM_TAG_ORIGINATION_EXPIRE_DATETIME"; + case KM_TAG_USAGE_EXPIRE_DATETIME: + return "KM_TAG_USAGE_EXPIRE_DATETIME"; + case KM_TAG_MIN_SECONDS_BETWEEN_OPS: + return "KM_TAG_MIN_SECONDS_BETWEEN_OPS"; + case KM_TAG_MAX_USES_PER_BOOT: + return "KM_TAG_MAX_USES_PER_BOOT"; + case KM_TAG_ALL_USERS: + return "KM_TAG_ALL_USERS"; + case KM_TAG_USER_ID: + return "KM_TAG_USER_ID"; + case KM_TAG_USER_SECURE_ID: + return "KM_TAG_USER_SECURE_ID"; + case KM_TAG_NO_AUTH_REQUIRED: + return "KM_TAG_NO_AUTH_REQUIRED"; + case KM_TAG_USER_AUTH_TYPE: + return "KM_TAG_USER_AUTH_TYPE"; + case KM_TAG_AUTH_TIMEOUT: + return "KM_TAG_AUTH_TIMEOUT"; + case KM_TAG_ALL_APPLICATIONS: + return "KM_TAG_ALL_APPLICATIONS"; + case KM_TAG_APPLICATION_ID: + return "KM_TAG_APPLICATION_ID"; + case KM_TAG_APPLICATION_DATA: + return "KM_TAG_APPLICATION_DATA"; + case KM_TAG_CREATION_DATETIME: + return "KM_TAG_CREATION_DATETIME"; + case KM_TAG_ORIGIN: + return "KM_TAG_ORIGIN"; + case KM_TAG_ROLLBACK_RESISTANT: + return "KM_TAG_ROLLBACK_RESISTANT"; + case KM_TAG_ROOT_OF_TRUST: + return "KM_TAG_ROOT_OF_TRUST"; + case KM_TAG_ASSOCIATED_DATA: + return "KM_TAG_ASSOCIATED_DATA"; + case KM_TAG_NONCE: + return "KM_TAG_NONCE"; + case KM_TAG_AUTH_TOKEN: + return "KM_TAG_AUTH_TOKEN"; + case KM_TAG_MAC_LENGTH: + return "KM_TAG_MAC_LENGTH"; + case KM_TAG_KDF: + return "KM_TAG_KDF"; + case KM_TAG_EC_CURVE: + return "KM_TAG_EC_CURVE"; + case KM_TAG_ECIES_SINGLE_HASH_MODE: + return "KM_TAG_ECIES_SINGLE_HASH_MODE"; + case KM_TAG_OS_VERSION: + return "KM_TAG_OS_VERSION"; + case KM_TAG_OS_PATCHLEVEL: + return "KM_TAG_OS_PATCHLEVEL"; + case KM_TAG_EXPORTABLE: + return "KM_TAG_EXPORTABLE"; + case KM_TAG_UNIQUE_ID: + return "KM_TAG_UNIQUE_ID"; + case KM_TAG_INCLUDE_UNIQUE_ID: + return "KM_TAG_INCLUDE_UNIQUE_ID"; + case KM_TAG_RESET_SINCE_ID_ROTATION: + return "KM_TAG_RESET_SINCE_ID_ROTATION"; + case KM_TAG_ALLOW_WHILE_ON_BODY: + return "KM_TAG_ALLOW_WHILE_ON_BODY"; + case KM_TAG_ATTESTATION_CHALLENGE: + return "KM_TAG_ATTESTATION_CHALLENGE"; + } + return "<Unknown>"; +} +#endif // KEYMASTER_NAME_TAGS + +// DEFINE_KEYMASTER_TAG is used to create TypedTag instances for each non-enum keymaster tag. +#define DEFINE_KEYMASTER_TAG(type, name) TypedTag<type, KM_##name> name + +DEFINE_KEYMASTER_TAG(KM_INVALID, TAG_INVALID); +DEFINE_KEYMASTER_TAG(KM_UINT, TAG_KEY_SIZE); +DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MAC_LENGTH); +DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_CALLER_NONCE); +DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MIN_MAC_LENGTH); +DEFINE_KEYMASTER_TAG(KM_ULONG, TAG_RSA_PUBLIC_EXPONENT); +DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ECIES_SINGLE_HASH_MODE); +DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_INCLUDE_UNIQUE_ID); +DEFINE_KEYMASTER_TAG(KM_DATE, TAG_ACTIVE_DATETIME); +DEFINE_KEYMASTER_TAG(KM_DATE, TAG_ORIGINATION_EXPIRE_DATETIME); +DEFINE_KEYMASTER_TAG(KM_DATE, TAG_USAGE_EXPIRE_DATETIME); +DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MIN_SECONDS_BETWEEN_OPS); +DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MAX_USES_PER_BOOT); +DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ALL_USERS); +DEFINE_KEYMASTER_TAG(KM_UINT, TAG_USER_ID); +DEFINE_KEYMASTER_TAG(KM_ULONG_REP, TAG_USER_SECURE_ID); +DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_NO_AUTH_REQUIRED); +DEFINE_KEYMASTER_TAG(KM_UINT, TAG_AUTH_TIMEOUT); +DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ALLOW_WHILE_ON_BODY); +DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ALL_APPLICATIONS); +DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_APPLICATION_ID); +DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_APPLICATION_DATA); +DEFINE_KEYMASTER_TAG(KM_DATE, TAG_CREATION_DATETIME); +DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ROLLBACK_RESISTANT); +DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ROOT_OF_TRUST); +DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ASSOCIATED_DATA); +DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_NONCE); +DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_AUTH_TOKEN); +DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_BOOTLOADER_ONLY); +DEFINE_KEYMASTER_TAG(KM_UINT, TAG_OS_VERSION); +DEFINE_KEYMASTER_TAG(KM_UINT, TAG_OS_PATCHLEVEL); +DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_UNIQUE_ID); + +// DEFINE_KEYMASTER_ENUM_TAG is used to create TypedEnumTag instances for each enum keymaster tag. + +#define DEFINE_KEYMASTER_ENUM_TAG(type, name, enumtype) TypedEnumTag<type, KM_##name, enumtype> name + +DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_PURPOSE, keymaster_purpose_t); +DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_ALGORITHM, keymaster_algorithm_t); +DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_BLOCK_MODE, keymaster_block_mode_t); +DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_DIGEST, keymaster_digest_t); +DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_DIGEST_OLD, keymaster_digest_t); +DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_PADDING, keymaster_padding_t); +DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_PADDING_OLD, keymaster_padding_t); +DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_BLOB_USAGE_REQUIREMENTS, + keymaster_key_blob_usage_requirements_t); +DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_ORIGIN, keymaster_key_origin_t); +DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_USER_AUTH_TYPE, hw_authenticator_type_t); +DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_KDF, keymaster_kdf_t); +DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_EC_CURVE, keymaster_ec_curve_t); + +} // namespace keymaster diff --git a/unit_test/nist_curve_key_exchange_test.cpp b/unit_test/nist_curve_key_exchange_test.cpp new file mode 100644 index 0000000..39ea38b --- a/dev/null +++ b/unit_test/nist_curve_key_exchange_test.cpp @@ -0,0 +1,219 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nist_curve_key_exchange.h" + +#include <gtest/gtest.h> +#include <openssl/evp.h> + +#include <hardware/keymaster_defs.h> +#include <keymaster/android_keymaster_utils.h> + +#include "android_keymaster_test_utils.h" + +using std::string; + +namespace keymaster { +namespace test { + +StdoutLogger logger; + +static const keymaster_ec_curve_t kEcCurves[] = {KM_EC_CURVE_P_224, KM_EC_CURVE_P_256, + KM_EC_CURVE_P_384, KM_EC_CURVE_P_521}; + +/** + * SharedKey just tests that the basic key exchange identity holds: that both + * parties end up with the same key. + */ +TEST(NistCurveKeyExchange, SharedKey) { + for (auto& curve : kEcCurves) { + AuthorizationSet kex_description( + AuthorizationSetBuilder().Authorization(TAG_EC_CURVE, curve)); + for (size_t j = 0; j < 5; j++) { + NistCurveKeyExchange* alice_keyex = NistCurveKeyExchange::GenerateKeyExchange(curve); + NistCurveKeyExchange* bob_keyex = NistCurveKeyExchange::GenerateKeyExchange(curve); + + ASSERT_TRUE(alice_keyex != nullptr); + ASSERT_TRUE(bob_keyex != nullptr); + + Buffer alice_public_value; + ASSERT_TRUE(alice_keyex->public_value(&alice_public_value)); + Buffer bob_public_value; + ASSERT_TRUE(bob_keyex->public_value(&bob_public_value)); + + Buffer alice_shared, bob_shared; + ASSERT_TRUE(alice_keyex->CalculateSharedKey(bob_public_value, &alice_shared)); + ASSERT_TRUE(bob_keyex->CalculateSharedKey(alice_public_value, &bob_shared)); + EXPECT_EQ(alice_shared.available_read(), bob_shared.available_read()); + EXPECT_EQ(0, memcmp(alice_shared.peek_read(), bob_shared.peek_read(), + alice_shared.available_read())); + } + } +} + +/* + * This test tries a key agreement with a false public key (i.e. with + * a point not on the curve.) + * The expected result of such a protocol should be that the + * key agreement fails and returns an error. +*/ +static const char* kInvalidPublicKeys[] = { + "04" // uncompressed public key + "deadbeef7f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287" + "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac", +}; + +TEST(NistCurveKeyExchange, InvalidPublicKey) { + for (auto& curve : kEcCurves) { + AuthorizationSet kex_description( + AuthorizationSetBuilder().Authorization(TAG_EC_CURVE, curve)); + KeyExchange* key_exchange = NistCurveKeyExchange::GenerateKeyExchange(curve); + ASSERT_TRUE(key_exchange != nullptr); + + string peer_public_key = hex2str(kInvalidPublicKeys[0]); + Buffer computed_shared_secret; + ASSERT_FALSE(key_exchange->CalculateSharedKey( + reinterpret_cast<const uint8_t*>(peer_public_key.data()), peer_public_key.size(), + &computed_shared_secret)); + } +} + +/** + * Test that key exchange fails when peer public key is the point at infinity. + */ +TEST(NistCurveKeyExchange, TestInfinity) { + for (auto& curve : kEcCurves) { + /* Obtain the point at infinity */ + EC_GROUP* group = ec_get_group(curve); + EC_POINT* point_at_infinity = EC_POINT_new(group); + EC_POINT_set_to_infinity(group, point_at_infinity); + EXPECT_EQ(1, EC_POINT_is_on_curve(group, point_at_infinity, nullptr)); + size_t field_len_in_bits; + ec_get_group_size(group, &field_len_in_bits); + size_t field_len = (field_len_in_bits + 7) / 8; + size_t public_key_len = (field_len * 2) + 1; + uint8_t* public_key = new uint8_t[public_key_len]; + public_key_len = EC_POINT_point2oct(group, point_at_infinity, POINT_CONVERSION_UNCOMPRESSED, + public_key, public_key_len, nullptr /* ctx */); + + /* Perform the key exchange */ + AuthorizationSet kex_description( + AuthorizationSetBuilder().Authorization(TAG_EC_CURVE, curve)); + NistCurveKeyExchange* key_exchange = NistCurveKeyExchange::GenerateKeyExchange(curve); + ASSERT_TRUE(key_exchange != nullptr); + Buffer computed_shared_secret; + /* It should fail */ + ASSERT_FALSE(key_exchange->CalculateSharedKey(reinterpret_cast<const uint8_t*>(public_key), + public_key_len, &computed_shared_secret)); + + /* Explicitly test that ECDH_compute_key fails when the public key is the point at infinity + */ + UniquePtr<uint8_t[]> result(new uint8_t[field_len]); + EXPECT_EQ(-1 /* error */, ECDH_compute_key(result.get(), field_len, point_at_infinity, + key_exchange->private_key(), nullptr /* kdf */)); + } +} + +/* Test vectors for P-256, downloaded from NIST. */ +struct NistCurveTest { + const keymaster_ec_curve_t curve; + const char* peer_public_key; + const char* my_private_key; + const char* shared_secret; +}; + +static const NistCurveTest kNistCurveTests[] = { + { + KM_EC_CURVE_P_256, + "04" // uncompressed public key + "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287" + "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac", + // https://tools.ietf.org/html/rfc5915 + "30770201010420" // DER-encodeded EC private key header + "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534" // private key + "a00a06082a8648ce3d030107a144034200" // DER-encoded curve OID, + "04" + "ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b230" + "28af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141", + "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b", + }, + { + KM_EC_CURVE_P_256, "04" + "809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7ae" + "b29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3", + // https://tools.ietf.org/html/rfc5915 + "30770201010420" // DER-encodeded EC private key header + "38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5" // private key + "a00a06082a8648ce3d030107a144034200" // DER-encoded curve OID, + "04" + "119f2f047902782ab0c9e27a54aff5eb9b964829ca99c06b02ddba95b0a3f6d0" + "8f52b726664cac366fc98ac7a012b2682cbd962e5acb544671d41b9445704d1d", + "057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67", + }, + { + KM_EC_CURVE_P_256, "04" + "df3989b9fa55495719b3cf46dccd28b5153f7808191dd518eff0c3cff2b705ed" + "422294ff46003429d739a33206c8752552c8ba54a270defc06e221e0feaf6ac4", + // https://tools.ietf.org/html/rfc5915 + "30770201010420" // DER-encodeded EC private key header + "207c43a79bfee03db6f4b944f53d2fb76cc49ef1c9c4d34d51b6c65c4db6932d" // private key + "a00a06082a8648ce3d030107a144034200" // DER-encoded curve OID, + "04" + "24277c33f450462dcb3d4801d57b9ced05188f16c28eda873258048cd1607e0d" + "c4789753e2b1f63b32ff014ec42cd6a69fac81dfe6d0d6fd4af372ae27c46f88", + "96441259534b80f6aee3d287a6bb17b5094dd4277d9e294f8fe73e48bf2a0024", + }, +}; + +/** + * Test that key exchange works with NIST test vectors. + */ +TEST(NistCurveKeyExchange, NistTestVectors) { + for (auto& test : kNistCurveTests) { + string private_key = hex2str(test.my_private_key); + string shared_secret = hex2str(test.shared_secret); + + const uint8_t* private_key_data = reinterpret_cast<const uint8_t*>(private_key.data()); + UniquePtr<EC_KEY, EC_KEY_Delete> ec_key( + d2i_ECPrivateKey(nullptr, &private_key_data, private_key.size())); + ASSERT_TRUE(ec_key.get() && EC_KEY_check_key(ec_key.get())); + + keymaster_error_t error; + NistCurveKeyExchange* key_exchange = new NistCurveKeyExchange(ec_key.release(), &error); + EXPECT_EQ(KM_ERROR_OK, error); + ASSERT_TRUE(key_exchange != nullptr); + + Buffer computed_shared_secret; + string peer_public_key = hex2str(test.peer_public_key); + ASSERT_TRUE(key_exchange->CalculateSharedKey( + reinterpret_cast<const uint8_t*>(peer_public_key.data()), peer_public_key.size(), + &computed_shared_secret)); + EXPECT_EQ(shared_secret.size(), computed_shared_secret.available_read()); + EXPECT_EQ(0, memcmp(shared_secret.data(), computed_shared_secret.peek_read(), + shared_secret.size())); + + for (size_t i = 0; i < peer_public_key.size(); i++) { + // randomly flip some bits in the peer public key to make it invalid + peer_public_key[i] ^= 0xff; + ASSERT_FALSE(key_exchange->CalculateSharedKey( + reinterpret_cast<const uint8_t*>(peer_public_key.data()), peer_public_key.size(), + &computed_shared_secret)); + } + } +} + +} // namespace test +} // namespace keymaster diff --git a/unit_test/openssl_utils.h b/unit_test/openssl_utils.h new file mode 100644 index 0000000..9fa6ec1 --- a/dev/null +++ b/unit_test/openssl_utils.h @@ -0,0 +1,100 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSTEM_KEYMASTER_OPENSSL_UTILS_H_ +#define SYSTEM_KEYMASTER_OPENSSL_UTILS_H_ + +#include <openssl/bn.h> +#include <openssl/ec.h> +#include <openssl/engine.h> +#include <openssl/evp.h> +#include <openssl/rsa.h> +#include <openssl/x509.h> + +#include <UniquePtr.h> + +#include <hardware/keymaster_defs.h> + +namespace keymaster { + +struct KeymasterKeyBlob; + +class EvpMdCtxCleaner { + public: + explicit EvpMdCtxCleaner(EVP_MD_CTX* ctx) : ctx_(ctx) {} + ~EvpMdCtxCleaner() { EVP_MD_CTX_cleanup(ctx_); } + + private: + EVP_MD_CTX* ctx_; +}; + +template <typename T, void (*FreeFunc)(T*)> struct OpenSslObjectDeleter { + void operator()(T* p) { FreeFunc(p); } +}; + +#define DEFINE_OPENSSL_OBJECT_POINTER(name) \ + typedef OpenSslObjectDeleter<name, name##_free> name##_Delete; \ + typedef UniquePtr<name, name##_Delete> name##_Ptr; + +DEFINE_OPENSSL_OBJECT_POINTER(ASN1_BIT_STRING) +DEFINE_OPENSSL_OBJECT_POINTER(ASN1_INTEGER) +DEFINE_OPENSSL_OBJECT_POINTER(ASN1_OBJECT) +DEFINE_OPENSSL_OBJECT_POINTER(ASN1_OCTET_STRING) +DEFINE_OPENSSL_OBJECT_POINTER(ASN1_TIME) +DEFINE_OPENSSL_OBJECT_POINTER(BN_CTX) +DEFINE_OPENSSL_OBJECT_POINTER(EC_GROUP) +DEFINE_OPENSSL_OBJECT_POINTER(EC_KEY) +DEFINE_OPENSSL_OBJECT_POINTER(EC_POINT) +DEFINE_OPENSSL_OBJECT_POINTER(ENGINE) +DEFINE_OPENSSL_OBJECT_POINTER(EVP_PKEY) +DEFINE_OPENSSL_OBJECT_POINTER(PKCS8_PRIV_KEY_INFO) +DEFINE_OPENSSL_OBJECT_POINTER(RSA) +DEFINE_OPENSSL_OBJECT_POINTER(X509) +DEFINE_OPENSSL_OBJECT_POINTER(X509_EXTENSION) +DEFINE_OPENSSL_OBJECT_POINTER(X509_NAME) + +typedef OpenSslObjectDeleter<BIGNUM, BN_free> BIGNUM_Delete; +typedef UniquePtr<BIGNUM, BIGNUM_Delete> BIGNUM_Ptr; + +keymaster_error_t ec_get_group_size(const EC_GROUP* group, size_t* key_size_bits); +EC_GROUP* ec_get_group(keymaster_ec_curve_t curve); + +/** + * Many OpenSSL APIs take ownership of an argument on success but don't free the argument on + * failure. This means we need to tell our scoped pointers when we've transferred ownership, without + * triggering a warning by not using the result of release(). + */ +template <typename T, typename Delete_T> +inline void release_because_ownership_transferred(UniquePtr<T, Delete_T>& p) { + T* val __attribute__((unused)) = p.release(); +} + +keymaster_error_t convert_pkcs8_blob_to_evp(const uint8_t* key_data, size_t key_length, + keymaster_algorithm_t expected_algorithm, + UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* pkey); + +keymaster_error_t KeyMaterialToEvpKey(keymaster_key_format_t key_format, + const KeymasterKeyBlob& key_material, + keymaster_algorithm_t expected_algorithm, + UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* evp_pkey); + +keymaster_error_t EvpKeyToKeyMaterial(const EVP_PKEY* evp_pkey, KeymasterKeyBlob* key_blob); + +size_t ec_group_size_bits(EC_KEY* ec_key); + +} // namespace keymaster + +#endif // SYSTEM_KEYMASTER_OPENSSL_UTILS_H_ diff --git a/unit_test/sw_rsa_attest_root.key.pem b/unit_test/sw_rsa_attest_root.key.pem new file mode 100644 index 0000000..387a852 --- a/dev/null +++ b/unit_test/sw_rsa_attest_root.key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQCia63rbi5EYe/VDoLmt5TRdSMfd5tjkWP/96r/C3JHTsAsQ+wz +fNes7UA+jCigZtX3hwszl94OuE4TQKuvpSe/lWmgMdsGUmX4RFlXYfC78hdLt0GA +ZMAoDo9Sd47b0ke2RekZyOmLw9vCkT/X11DEHTVm+Vfkl5YLCazOkjWFmwIDAQAB +AoGAU8dxXchmqzVNbbvff7zgUa63YErk51Yem/EXzhkMaIXRkMO0edaCtZtnkRvg +9OQ2qEiLWaCTlUoyU7H/HUn2lwTQsOXyZI7dHijVDRMIv1mmrHCrGW/JC8FXfPLS +r3L3KoHXQVYL2mslbR8Rpogxq4WwnwK6XqSTH9mynFwQwEkCQQDMX3EZk3ricWVH +ruXD0BpXOMMpZuLu4rg5+1L51WEJvItIMeSjLuNa+g3AI8AYTYYi/aSLk6XEv82L +iXFGmJ2XAkEAy3M8k8Z0QzHae4olduqoHVWEarBtDE+fqFQBWgdm8fZhdHWrvlAc +qwJIXMUVc+dWm/FAQarCjbqWqhCRdaYgnQJBAJ7z7GdUCVNtlrQ2F4ZAqPwFreTZ +nM7njxmpm1Os3hhQiJPSGl3A7huoOGGkbJd6VEWKuRvF7jwkYZ2RfITH1mkCQAvh +X9E1Toa5+4spRwTJsSV9X+0m/kcwwx7+QNH0CrPockptsKi9Xt8xk+4u6BDLmogi +r2DmStQh6DhoHUZkfBUCQQCOgBkqH/15drpdR+BQH3VaP4/ALFfxR9E3G+lS+M5a +IqJEk9kh8vjuGzTaAZyU5keUmpWNc1gI7OvDMaH4+8vQ +-----END RSA PRIVATE KEY----- |