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.