Author: wmb Date: 2009-08-28 23:40:06 +0200 (Fri, 28 Aug 2009) New Revision: 1337
Modified: cpu/x86/pc/olpc/crypto.fth cpu/x86/pc/olpc/security.fth cpu/x86/pc/olpc/versions.fth cpu/x86/pc/olpc/via/versions.fth Log: OLPC trac 9045 - added support for delegated keys - sig02: format.
Modified: cpu/x86/pc/olpc/crypto.fth =================================================================== --- cpu/x86/pc/olpc/crypto.fth 2009-08-28 20:10:46 UTC (rev 1336) +++ cpu/x86/pc/olpc/crypto.fth 2009-08-28 21:40:06 UTC (rev 1337) @@ -19,8 +19,10 @@
: signature-bad? ( data$ sig$ key$ hashname$ -- mismatch? ) $cstr - verify-bss /verify-bss erase ( data$ sig$ key$ 'hashname ) - verify-base verify-stack sp-call >r 3drop 4drop r> ( result ) + verify-bss /verify-bss erase ( 0 data$ sig$ key$ 'hashname ) + verify-base verify-stack sp-call >r ( 0 data$ sig$ key$ 'hashname ) + 3drop 4drop begin 0= until ( ) + r> ( result ) ;
\ This is a hack that saves a lot of memory. The crypto verifier @@ -33,7 +35,7 @@ variable hashlen d# 128 buffer: hashbuf : crypto-hash ( data$ hashname$ -- result$ ) - 2>r hashbuf d# 128 hashlen 0 2r> ( data$ sig$ key$ hashname$ ) + 2>r 0 -rot hashbuf d# 128 hashlen 0 2r> ( 0 data$ sig$ key$ hashname$ ) signature-bad? abort" Hash failed" ( ) hashbuf hashlen @ ;
Modified: cpu/x86/pc/olpc/security.fth =================================================================== --- cpu/x86/pc/olpc/security.fth 2009-08-28 20:10:46 UTC (rev 1336) +++ cpu/x86/pc/olpc/security.fth 2009-08-28 21:40:06 UTC (rev 1337) @@ -196,90 +196,6 @@ sig-buf tuck - false ( sig$ false ) ;
-\ parse-sig parses a "sig01:" format signature string, returning its -\ hashname and signature substrings. It converts the signature -\ substring from ASCII hex to binary bytes. - -: parse-sig ( sig01$ -- true | hashname$ sig$ false ) - dup d# 89 < if 2drop true exit then - bl left-parse-string " sig01:" $= 0= if 2drop true exit then ( rem$ ) - bl left-parse-string dup d# 6 <> if 4drop true exit then 2swap ( hash$ rem$ ) - bl left-parse-string nip d# 64 <> if 4drop true exit then ( hash$ rem$ ) - newline left-parse-string 2swap nip 0<> if 4drop true exit then ( hash$ data$ ) - dup /sig 2* <> if ( ." Bad signature length" cr ) 2drop true exit then ( hash$ data$ ) - - hex-decode if 2drop true else false then -; - -\ zip-extent looks inside a memory-resident ZIP archive and returns -\ the address,length of a given component of that archive. This -\ assumes that the components are "stored", not "deflated". It -\ depends on the existence of a support package named "/lzip" to -\ do the work. - -: zip-extent ( name$ -- adr len ) - expand$ open-dev ?dup 0= if " " exit then - >r - " offset" r@ $call-method load-base + - " size" r@ $call-method drop - r> close-dev -; - -\ sig$ and img$ find the signature and signed-image components of -\ a ZIP bundle image that is already in memory. - -: sig$ ( -- adr len ) " /lzip:\data.sig" zip-extent ; -: img$ ( -- adr len ) " /lzip:\data.img" zip-extent ; - -\ bundle-name$ returns the full OFW pathname of a signed image -\ bundle, piecing it together from the device (DN), path (PN), -\ filename head (CN), and filename body (FN) macros. - -: bundle-name$ ( -- $ ) " ${DN}${PN}${CN}${FN}.zip" expand$ ; - -\ bundle-present? determines the existence (or not) of a signed image -\ bundle whose name is constructed from the current settings of the -\ device (DN), path (PN), filename head (CN), and filename body (FN). - -: .trying ( name$ -- name$ ) - " Trying " ?lease-debug 2dup ?lease-debug-cr -; -: bundle-present? ( fn$ -- flag ) - fn-buf place - bundle-name$ .trying - ['] (boot-read) catch if 2drop false exit then - true -; - -\ hashname remembers the most recently used hashname to guard against -\ attacks based on reuse of the same (presumably compromized) hash. - -\ signature-invalid? checks the validity of data$ against the ASCII signature -\ record sig01$, using the public key that thiskey$ points to. -\ It also verifies that the hashname contained in sig01$ is the -\ expected one. - -: signature-invalid? ( data$ sig01$ exp-hashname$ -- error? ) - 2>r - parse-sig if - ." Bad signature format" cr - 2r> 2drop true exit - then ( data$ hashname$ sig$ r: exp$ ) - - \ Check for duplicate hashname attacks - 2swap 2dup 2r> $= 0= if ( data$ sig$ hashname$ ) - ." Wrong hash name" cr - 4drop 2drop true exit - then ( data$ sig$ hashname$ ) - - thiskey$ 2swap signature-bad? ( error? ) - dup if - " Signature invalid" ?lease-error-cr - else - " Signature valid" ?lease-debug-cr - then -; - \ cut$ splits a string into an initial substring of length n \ (head$) and the residual substring (tail$). If the input \ string is shorter than n, head$ is the input string and tail$ is @@ -291,12 +207,23 @@ over r@ - r> ( tail$ head$ ) ;
-: sig01$>key$ ( sig01$ -- true | binary-key$ false ) - bl left-parse-string " sig01:" $= 0= if 2drop true exit then ( rem$ ) - bl left-parse-string 2drop \ Discard hash name ( rem$ ) - bl left-parse-string 2nip \ Get key signature ( key$ ) - /sig 2* min hex-decode if 2drop true exit then ( binary-key$ ) - false +: sig$>key$ ( sig0N$ -- true | binary-key$ false ) + bl left-parse-string ( rem$ signame$ ) + 2dup " sig01:" $= if ( rem$ signame$ ) + 2drop ( rem$ ) + else ( rem$ signame$ ) + " sig02:" $= 0= if ( rem$ ) + 2drop true ( true ) + exit + then ( rem$ ) + then ( rem$ ) + bl left-parse-string 2drop ( rem$ ) \ Discard hash name + bl left-parse-string 2nip ( key$ ) \ Get key signature + /sig 2* min hex-decode if ( key$ ) + 2drop true ( true ) + exit + then ( binary-key$ ) + false ( binary-key$ false ) ;
\ True if short$ matches the end of long$ @@ -316,19 +243,14 @@ 2r> 4drop false ;
-: in-pubkey-list? ( sig01$ -- flag ) - sig01$>key$ if false exit then ( key$ ) - key-in-list? ( flag ) +: in-pubkey-list? ( sig0N$ -- flag ) + sig$>key$ if false exit then ( key$ ) + key-in-list? ( flag ) ;
-: our-pubkey? ( sig01$ -- flag ) - sig01$>key$ if false exit then ( key$ ) - thiskey$ tail$= ( flag ) -; - -\ Look for a line that starts with "sig01: " whose key signature +\ Look for a line that starts with "sig0N: " whose key signature \ matches the trailing bytes of a public key in our current list. -: next-sig01-in-list$ ( sig$ -- true | rem$ sig01$ false ) +: next-sig-in-list$ ( sig$ -- true | rem$ sig0N$ false ) begin dup while ( rem$ ) newline left-parse-string ( rem$' line$ ) 2dup in-pubkey-list? if false exit then ( rem$ line$ ) @@ -338,36 +260,27 @@ 2drop true ;
-\ Look for a line that starts with "sig01: " whose key signature +\ Look for a line that starts with "sig0N: " whose key signature \ matches the trailing bytes of our currently-selected public key. -: next-sig01$ ( sig$ -- true | rem$ sig01$ false ) - begin dup while ( rem$ ) - newline left-parse-string ( rem$' line$ ) - 2dup our-pubkey? if false exit then ( rem$ line$ ) - 2drop ( rem$ ) - repeat ( rem$ ) +\ This differs from next-sig-in-list$ in that next-sig-in-list$ +\ looks for a signature that matches any public key in our list, +\ whereas this looks for a second signature that matches the public +\ key that next-sig-in-list$ already found. +: next-sig$ ( sig$ -- true | rem$ sig0N$ false ) + begin dup while ( rem$ ) + newline left-parse-string ( rem$' line$ ) + 2dup sig$>key$ 0= if ( rem$ line$ binary-key$ ) + thiskey$ tail$= if ( rem$ line$ ) + false ( rem$ sig0N$ false ) + exit + then ( rem$ line$ ) + then ( rem$ line$ ) + 2drop ( rem$ ) + repeat ( rem$ ) " No signature for our key" ?lease-error-cr 2drop true ;
-\ Find a sig01: line and check its sha256/rsa signature -: sha-valid? ( data$ sig01$ -- okay? ) - next-sig01-in-list$ if 2drop false exit then ( data$ rem$ sig01$ ) - 2nip " sha256" signature-invalid? 0= -; - -\ Find two sig01: lines, the first with sha256 and the second with rmd160, -\ and check their signatures -: fw-valid? ( data$ sig$ -- okay? ) - 2swap 2>r ( sig$ r: data$ ) - next-sig01-in-list$ if 2r> 2drop false exit then ( rem$ sig01$ ) - 2r@ 2swap sha-valid? 0= if ( rem$ r: data$ ) - 2r> 4drop false exit - then ( rmd-sig$ r: data$ ) - next-sig01$ if 2r> 2drop false exit then ( rem$ sig01$ ) - 2nip 2r> 2swap " rmd160" signature-invalid? 0= -; - \ numfield is a factor used for parsing 2-digit fields from date/time strings. : numfield ( exp$ min max -- exp$' ) >r >r ( exp$ r: max min ) @@ -409,7 +322,7 @@
\ earliest is the earliest acceptable date value (in seconds). \ It is the date that the first test version of this code was - \ deployed. If a laptop has any earlier date that than, that + \ deployed. If a laptop has any earlier date, the \ date is presumed bogus.
current-seconds [ " 20070101T000000Z" expiration-to-seconds drop ] literal - 0< @@ -420,6 +333,9 @@ \ earlier than this machine's current time (from the real time clock).
: expired? ( expiration$ -- bad? ) + \ Check for non-expiring case + 2dup " 00000000T000000Z" $= if 2drop false exit then + expiration-to-seconds if true exit then ( seconds )
\ If the date is bad, leases are deemed to have expired @@ -428,9 +344,6 @@ current-seconds - 0< ;
-d# 1024 constant /sec-line-max -/sec-line-max buffer: sec-line-buf - \ machine-id-buf is a buffer into which the machine signature string, \ including serial number, UUID, and expiration time, is place. \ That string is the signed object for lease and developer key verification. @@ -478,10 +391,259 @@ : my-sn$ ( -- adr len ) machine-id-buf d# 11 ;
+\ parse-sig parses a "sig01:" format signature string, returning its +\ hashname and signature substrings. It converts the signature +\ substring from ASCII hex to binary bytes. + +: parse-sig ( sig01$ -- true | hashname$ sig$ false ) + dup d# 89 < if 2drop true exit then + bl left-parse-string " sig01:" $= 0= if 2drop true exit then ( rem$ ) + bl left-parse-string dup d# 6 <> if 4drop true exit then 2swap ( hash$ rem$ ) + bl left-parse-string nip d# 64 <> if 4drop true exit then ( hash$ rem$ ) + newline left-parse-string 2swap nip 0<> if 4drop true exit then ( hash$ data$ ) + dup /sig 2* <> if ( ." Bad signature length" cr ) 2drop true exit then ( hash$ data$ ) + + hex-decode if 2drop true else false then +; + +\ zip-extent looks inside a memory-resident ZIP archive and returns +\ the address,length of a given component of that archive. This +\ assumes that the components are "stored", not "deflated". It +\ depends on the existence of a support package named "/lzip" to +\ do the work. + +: zip-extent ( name$ -- adr len ) + expand$ open-dev ?dup 0= if " " exit then + >r + " offset" r@ $call-method load-base + + " size" r@ $call-method drop + r> close-dev +; + +\ sig$ and img$ find the signature and signed-image components of +\ a ZIP bundle image that is already in memory. + +: sig$ ( -- adr len ) " /lzip:\data.sig" zip-extent ; +: img$ ( -- adr len ) " /lzip:\data.img" zip-extent ; + +\ bundle-name$ returns the full OFW pathname of a signed image +\ bundle, piecing it together from the device (DN), path (PN), +\ filename head (CN), and filename body (FN) macros. + +: bundle-name$ ( -- $ ) " ${DN}${PN}${CN}${FN}.zip" expand$ ; + +\ bundle-present? determines the existence (or not) of a signed image +\ bundle whose name is constructed from the current settings of the +\ device (DN), path (PN), filename head (CN), and filename body (FN). + +: .trying ( name$ -- name$ ) + " Trying " ?lease-debug 2dup ?lease-debug-cr +; +: bundle-present? ( fn$ -- flag ) + fn-buf place + bundle-name$ .trying + ['] (boot-read) catch if 2drop false exit then + true +; + +\ hashname remembers the most recently used hashname to guard against +\ attacks based on reuse of the same (presumably compromized) hash. + +0 [if] +\ signature-invalid? checks the validity of data$ against the ASCII signature +\ record sig0N$, using the public key that thiskey$ points to. +\ It also verifies that the hashname contained in sig01$ is the +\ expected one. + +: signature-invalid? ( data$ sig0N$ exp-hashname$ -- error? ) + 2>r + parse-sig if + ." Bad signature format" cr + 2r> 2drop true exit + then ( data$ hashname$ sig$ r: exp$ ) + + \ Check for duplicate hashname attacks + 2swap 2dup 2r> $= 0= if ( data$ sig$ hashname$ ) + ." Wrong hash name" cr + 4drop 2drop true exit + then ( data$ sig$ hashname$ ) + + 2>r 2>r 2>r 0 2r> 2r> 2r> ( 0 data$ sig$ hashname$ ) + pubkey$ 2swap signature-bad? ( error? ) + dup if + " Signature invalid" ?lease-error-cr + else + " Signature valid" ?lease-debug-cr + then +; +[then] + +0 0 2value exp-hashname$ +0 0 2value signed-data$ + +\ sig01: hashname keyid signature +: sig01-good? ( line$ -- good? ) + \ Check that the hashname is as expected + bl left-parse-string ( line$ this-hashname$ ) + exp-hashname$ $= 0= if ( line$ ) + 2drop false exit + then ( line$' ) + + \ Check that the keyid matches our pubkey + bl left-parse-string ( line$' keyid$ ) + /sig 2* min hex-decode if ( line$ ) + 2drop false exit + then ( line$ binary-key$ ) + + key-in-list? 0= if ( line$ ) + 2drop false exit + then ( line$ ) + + \ Check that the signature occupies the rest of the line + bl left-parse-string ( line$' sig$ ) + 2swap nip 0<> if ( sig$ ) + \ Trailing junk at the end + 2drop false exit + then ( sig$ ) + + dup /sig 2* <> if ( sig$ ) + 2drop false exit + then ( sig$ ) + + hex-decode if ( ) + false exit + then ( binary-sig$ ) + + \ Cryptographically verify the data against the signature + 2>r 0 signed-data$ 2r> thiskey$ exp-hashname$ signature-bad? 0= +; + +h# 10e constant /key +/key buffer: keybuf + +0 0 2value sig02-key$ + +0 0 2value expiry$ + +: sig02-good? ( line$ -- good? ) + d# 100 0 do + \ Check that the hashname is as expected + bl left-parse-string ( line$' this-hashname$ ) + exp-hashname$ $= 0= if ( line$ ) + 2drop false unloop exit + then ( line$' ) + + \ Check that the keyid matches our pubkey, but only if it's + \ the first one + bl left-parse-string ( line$' pubkey$ ) + hex-decode if ( line$ ) + 2drop false unloop exit + then ( line$ binary-key$ ) + + i if ( line$ binary-key$ ) + dup /key <> if ( line$ binary-key$ ) + 4drop false unloop exit + then ( line$ binary-key$ ) + tuck keybuf swap move ( line$ binary-keylen ) + keybuf swap ( line$ binary-key$' ) + else ( line$ binary-keyid$ ) + key-in-list? 0= if ( line$ ) + 2drop false unloop exit + then ( line$ ) + thiskey$ ( line$ key$ ) + then ( line$ key$ ) + to sig02-key$ ( line$ ) + + \ Check the expiration date + bl left-parse-string to expiry$ ( line$' ) + expiry$ expired? if ( line$ ) + 2drop false unloop exit + then ( line$ ) + + \ Get the signature + bl left-parse-string ( line$ sig$) + + dup /sig 2* <> if ( line$ sig$ ) + 4drop false unloop exit + then ( line sig$ ) + + hex-decode if ( line$ ) + 2drop false unloop exit + then ( line$ binary-sig$ ) + + 2>r ( line$' r: binary-sig$ ) + + \ If it's the final signature, check the signed data + dup 0= if ( line$ r: sig$ ) + 2drop ( r: sig$ ) + 0 signed-data$ " :" expiry$ " :" my-sn$ 2r> ( 0 data$ .. sig$ ) + sig02-key$ exp-hashname$ signature-bad? 0= ( good? ) + unloop exit + then ( line$ r: sig$ ) + + \ Otherwise check the next key in the list + 2dup bl left-parse-string 2drop ( line$ line$' r: sig$ ) \ Discard the hashname + bl left-parse-string 2nip 2>r ( line$ r: sig$ key$ ) + + 0 " "n" 2r> " :key01: " expiry$ " :" my-sn$ 2r> ( 0 data$ .. sig$ ) + sig02-key$ exp-hashname$ signature-bad? if ( line$ ) + 2drop false unloop exit + then ( line$ ) + loop + true abort" Delegation too long" +; + +: this-sig-line-good? ( line$ -- good? ) + bl left-parse-string ( line$' tag$ ) + 2dup " sig01:" $= if ( line$' tag$ ) + 2drop sig01-good? ( good? ) + exit + then ( line$' ) + 2dup " sig02:" $= if ( line$' tag$ ) + 2drop sig02-good? ( good? ) + exit + then ( line$' tag$ ) + 4drop false ( good? ) +; + +: signature-good? ( data$ sig$ hashname$ -- good? ) + to exp-hashname$ ( data$ sig$ ) + 2swap to signed-data$ ( sig$ ) + begin dup while ( rem$ ) + newline left-parse-string ( rem$' line$ ) + + this-sig-line-good? if ( rem$ ) + 2drop true exit + then ( rem$ ) + + repeat ( rem$ ) + 2drop false ( good? ) +; + +\ Find a sig0N: line and check its sha256/rsa signature +: sha-valid? ( data$ sig01$ -- okay? ) + next-sig-in-list$ if 2drop false exit then ( data$ rem$ sig01$ ) + \ 2nip " sha256" signature-invalid? 0= + 2nip " sha256" signature-good? +; + +\ Find two sig0N: lines, the first with sha256 and the second with rmd160, +\ and check their signatures +: fw-valid? ( data$ sig$ -- okay? ) + 2swap 2>r ( sig$ r: data$ ) + next-sig-in-list$ if 2r> 2drop false exit then ( rem$ sig01$ ) + 2r@ 2swap sha-valid? 0= if ( rem$ r: data$ ) + 2r> 4drop false exit + then ( rmd-sig$ r: data$ ) + next-sig$ if 2r> 2drop false exit then ( rem$ sig01$ ) +\ 2nip 2r> 2swap " rmd160" signature-invalid? 0= + 2nip 2r> 2swap " rmd160" signature-good? +; + +d# 1024 constant /sec-line-max +/sec-line-max buffer: sec-line-buf + : check-expiry ( exp$ -- exp$ -1|0 ) - \ Check for non-expiring case - 2dup " 00000000T000000Z" $= if 0 exit then - dup d# 16 <> if ( expiration$ ) " has bad expiration format" ?lease-error-cr -1 exit @@ -504,7 +666,8 @@ 2over in-pubkey-list? if ( sig$ exp$ ) machine-id-buf d# 51 + swap move ( sig$ ) machine-id-buf d# 67 2swap ( id$ sig$ ) - " sha256" signature-invalid? if -1 else 1 then ( -1|1 ) + \ " sha256" signature-invalid? if -1 else 1 then ( -1|1 ) + " sha256" signature-good? if 1 else -1 then ( -1|1 ) else ( sig$ exp$ ) 4drop 0 ( 0 ) then ( -1|0|1 )
Modified: cpu/x86/pc/olpc/versions.fth =================================================================== --- cpu/x86/pc/olpc/versions.fth 2009-08-28 20:10:46 UTC (rev 1336) +++ cpu/x86/pc/olpc/versions.fth 2009-08-28 21:40:06 UTC (rev 1337) @@ -19,7 +19,7 @@ macro: WLAN_VERSION 5.110.22.p23
\ The bios_verify image -macro: CRYPTO_VERSION 0.2 +macro: CRYPTO_VERSION 0.4
\ The multicast NAND updater code version \ Use a specific git commit ID for a formal release or "test" for development.
Modified: cpu/x86/pc/olpc/via/versions.fth =================================================================== --- cpu/x86/pc/olpc/via/versions.fth 2009-08-28 20:10:46 UTC (rev 1336) +++ cpu/x86/pc/olpc/via/versions.fth 2009-08-28 21:40:06 UTC (rev 1337) @@ -2,7 +2,7 @@
\ The overall firmware revision macro: FW_MAJOR A -macro: FW_MINOR 10 +macro: FW_MINOR 10a
\ The EC microcode macro: EC_VERSION 1_9_9 @@ -23,7 +23,7 @@ \ macro: GET_WLAN cp "/c/Documents and Settings/Mitch Bradley/My Documents/OLPC/DiskImages/sd8686-9.70.7.p0.bin" sd8686.bin; cp "/c/Documents and Settings/Mitch Bradley/My Documents/OLPC/DiskImages/sd8686_helper.bin" sd8686_helper.bin
\ The bios_verify image -macro: CRYPTO_VERSION 0.2 +macro: CRYPTO_VERSION 0.4
\ The multicast NAND updater code version \ Use a specific git commit ID for a formal release or "test" for development.
openfirmware@openfirmware.info