Author: wmb Date: 2009-01-28 01:17:24 +0100 (Wed, 28 Jan 2009) New Revision: 1084
Modified: cpu/x86/pc/olpc/fsupdate.fth cpu/x86/pc/olpc/security.fth cpu/x86/pc/olpc/setwp.fth Log: OLPC trac 9045 - added multiple key support as defined by http://wiki.laptop.org/go/Firmware_security
Modified: cpu/x86/pc/olpc/fsupdate.fth =================================================================== --- cpu/x86/pc/olpc/fsupdate.fth 2009-01-23 21:57:21 UTC (rev 1083) +++ cpu/x86/pc/olpc/fsupdate.fth 2009-01-28 00:17:24 UTC (rev 1084) @@ -169,7 +169,7 @@ null$ cn-buf place ( rem$ ) " fs" bundle-present? if ( rem$ ) " Filesystem image found - " ?lease-debug - fskey$ to pubkey$ ( rem$ ) + fskey$ to pubkeylist$ ( rem$ ) img$ sig$ sha-valid? if ( rem$ ) 2drop ( ) show-unlock ( )
Modified: cpu/x86/pc/olpc/security.fth =================================================================== --- cpu/x86/pc/olpc/security.fth 2009-01-23 21:57:21 UTC (rev 1083) +++ cpu/x86/pc/olpc/security.fth 2009-01-28 00:17:24 UTC (rev 1084) @@ -101,30 +101,111 @@ : PN pn-buf count ; previous definitions
+0 0 2value pubkeylist$ \ adr,len of a concatenated sequence of keys +0 value pubkeylen \ Length of each key in the list + +\ Copy a string to allocated memory +: preserve$ ( $ -- $' ) + >r ( adr1 r: len ) + r@ alloc-mem ( adr1 adr2 ) + tuck r@ move r> ( $' ) +; + +\ find-key-tag finds a tag like "s0" or "s8". The caller sets tagname[0] +\ to 's' and then calls find-key-tag with different "n" arguments. + +2 buffer: tagname +: find-key-tag ( n -- false | value$ true ) + [char] 0 + tagname 1+ c! + tagname 2 find-tag +; + +: ?bad-tag-len ( explen actlen -- ) + <> if + ." Warning - override key length mismatch for tag " tagname 2 type cr + then +; + +\ Count the number of additional keys, so we know how much memory to allocate + +: #augment-keys ( keylen -- n ) + 0 d# 10 1 do ( len n ) + i find-key-tag if ( len n value$ ) + nip 2 pick ?bad-tag-len ( len n ) + 1+ ( len n' ) + then ( len n ) + loop ( len n ) + nip +; + +\ Amend the key list string with alternative or additional keys from +\ manufacturing data. + +: augment-key$ ( olpc-key$ mfg-data$ -- key$' ) + tagname swap move ( key$ ) + + 0 find-key-tag if ( key$ value$ ) + \ If we have an override key with tag suffix 0, replace the OLPC key + 2 pick over ?bad-tag-len ( key$ value$ ) + + 2swap free-mem ( value$ ) + preserve$ ( key$' ) + exit + then ( key$ ) + + \ Otherwise add augment keys to the list ( key$ ) + \ First determine how much memory to allocate + dup #augment-keys 1+ ( key$ #extra ) + over * dup alloc-mem swap ( key$ total$ ) + 2over 2over drop ( key$ total$ key$ total-adr ) + swap move ( key$ total$ ) + 2swap tuck free-mem ( total$ keylen ) + 2 pick over + ( total$ keylen curadr ) + d# 10 1 do ( total$ keylen curadr ) + i find-key-tag if ( total$ keylen curadr value$ ) + drop over 3 pick move ( total$ keylen curadr ) + over + ( total$ keylen curadr' ) + then ( total$ keylen curadr ) + loop ( total$ keylen curadr ) + 2drop ( total$ ) +; + \ key: is a defining word whose children return key strings. \ Each child word has the name of its key stored in the dictionary. \ The first time that a child word executes, it uses the key name \ to find the key value and caches the key value in RAM so subsequent \ uses are faster.
+\ The key name includes both the name that is used in the dropin +\ module list (e.g. "fspubkey") and the prefix letter for mfg data +\ tags (e.g. "s"). + : key: ( name$ "name" -- key$ ) create 0 , 0 , ", \ adr len name does> ( apf -- key$ ) dup @ if 2@ exit then ( apf ) dup 2 na+ count ( apf name$ ) - 2dup find-drop-in if ( apf name$ key$ ) - 2nip - else ( apf name$ ) - ." Can't load key " type cr + [char] , left-parse-string ( apf mfg-data$ dropin-name$ ) + 2dup find-drop-in if ( apf mfg-data$ name$ key$ ) + 2nip ( apf mfg-data$ key$ ) + else ( apf mfg-data$ name$ ) + ." Can't load key " type cr ( apf mfg-data$ ) + 2drop ( apf ) " Missing Key" ( apf bad-key$ ) - then + dup to pubkeylen ( apf bad-key$ ) + rot >r 2dup r> 2! ( key$ ) + exit + then ( apf mfg-data$ key$ ) + dup to pubkeylen ( apf mfg-data$ key$ ) + 2swap ( apf key$ mfg-data$ ) + augment-key$ ( apf key$' ) rot >r 2dup r> 2! ( key$ ) ; -" fspubkey" key: fskey$ -" ospubkey" key: oskey$ -" fwpubkey" key: fwkey$ -" develpubkey" key: develkey$ -" leasepubkey" key: leasekey$ +" fspubkey,s" key: fskey$ +" ospubkey,o" key: oskey$ +" fwpubkey,w" key: fwkey$ +" develpubkey,d" key: develkey$ +" leasepubkey,a" key: leasekey$
\ pubkey$ is a global variable that points to the currently-selected \ public key string. It simplifies the stack manipulations for other @@ -235,29 +316,79 @@ then ;
-: our-pubkey? ( sig01$ -- flag ) - bl left-parse-string " sig01:" $= 0= if 2drop false exit then ( rem$ ) +\ break$ 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 +\ the null string. + +: break$ ( $ n -- tail$ head$ ) + 2dup < if drop null$ 2swap exit then + dup >r /string ( tail$ ) + 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 false exit then ( binary-key$ ) - pubkey$ dup 3 pick - 0 max /string $= ( flag ) + /sig 2* min hex-decode if 2drop true exit then ( binary-key$ ) + false ;
-\ Look for a line that starts with "sig01: " and whose key signature +\ True if short$ matches the end of long$ +: tail$= ( short$ long$ -- flag ) 2 pick - + swap comp 0= ; + +: key-in-list? ( key$ -- flag ) \ Sets pubkey$ as an important side effect + 2>r ( r: key$ ) + pubkeylist$ begin dup while ( rem$ r: key$ ) + pubkeylen break$ ( rem$' pubkey$ r: key$ ) + 2r@ 2over tail$= if ( rem$ pubkey$ r: key$ ) + to pubkey$ ( rem$ r: key$ ) + 2r> 4drop true ( true ) + exit + then ( rem$' pubkey$ r: key$ ) + 2drop ( rem$' r: key$ ) + repeat ( rem$' r: key$ ) + 2r> 4drop false +; + +: in-pubkey-list? ( sig01$ -- flag ) + sig01$>key$ if false exit then ( key$ ) + key-in-list? ( flag ) +; + +: our-pubkey? ( sig01$ -- flag ) + sig01$>key$ if false exit then ( key$ ) + pubkey$ tail$= ( flag ) +; + +\ Look for a line that starts with "sig01: " whose key signature +\ matches the trailing bytes of a public key in our current list. +: next-sig01-in-list$ ( sig$ -- true | rem$ sig01$ false ) + begin dup while ( rem$ ) + newline left-parse-string ( rem$' line$ ) + 2dup in-pubkey-list? if false exit then ( rem$ line$ ) + 2drop ( rem$ ) + repeat ( rem$ ) + " No signature for our key list" ?lease-error-cr + 2drop true +; + +\ Look for a line that starts with "sig01: " 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$ ) + begin dup while ( rem$ ) + newline left-parse-string ( rem$' line$ ) + 2dup our-pubkey? if false exit 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$ if 2drop false exit then ( data$ rem$ sig01$ ) + next-sig01-in-list$ if 2drop false exit then ( data$ rem$ sig01$ ) 2nip " sha256" invalid? 0= ;
@@ -265,7 +396,7 @@ \ and check their signatures : fw-valid? ( data$ sig$ -- okay? ) 2swap 2>r ( sig$ r: data$ ) - next-sig01$ if 2r> 2drop false exit then ( rem$ sig01$ ) + 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$ ) @@ -273,17 +404,6 @@ 2nip 2r> 2swap " rmd160" invalid? 0= ;
-\ break$ 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 -\ the null string. - -: break$ ( $ n -- tail$ head$ ) - 2dup < if drop null$ 2swap exit then - dup >r /string ( tail$ ) - over r@ - r> ( tail$ head$ ) -; - \ 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 ) @@ -417,7 +537,7 @@ \ doesn't match our pubkey.
: check-machine-signature ( sig$ expiration$ -- -1|1 ) - 2over our-pubkey? if ( sig$ exp$ ) + 2over in-pubkey-list? if ( sig$ exp$ ) machine-id-buf d# 51 + swap move ( sig$ ) machine-id-buf d# 67 2swap ( id$ sig$ ) " sha256" invalid? if -1 else 1 then ( -1|1 ) @@ -487,7 +607,7 @@ " lease.sig" open-security? if drop false exit then >r ( r: ih ) " Lease " ?lease-debug load-started - leasekey$ to pubkey$ + leasekey$ to pubkeylist$ begin sec-line-buf /sec-line-max r@ read-line if ( actual -eof? ) 2drop r> close-file drop false exit @@ -497,7 +617,8 @@ 1 of r> close-file drop " unlock" show-icon true exit endof -1 of r> close-file drop " lock" show-icon false exit endof endcase - repeat + repeat ( actual ) + drop ( ) " No matching records" ?lease-error-cr r> close-file drop false ; @@ -622,7 +743,7 @@ " develop.sig" open-security? if drop false exit then >r ( r: ih ) " Devel key " ?lease-debug load-started - develkey$ to pubkey$ + develkey$ to pubkeylist$ begin sec-line-buf /sec-line-max r@ read-line if ( actual -eof? ) 2drop r> close-file drop false exit @@ -717,6 +838,19 @@ " Reflash returned, unexpectedly" .security-failure ;
+\ Turn off indexed I/O unless the OS is signed with the firmware +\ key in addition to the OS key. + +: ?disable-indexed-io ( -- ) + debug-security? >r false to debug-security? + pubkeylist$ 2>r fwkey$ to pubkeylist$ + + img$ sig$ fw-valid? 0= if ec-indexed-io-off then + + 2r> to pubkeylist$ + r> to debug-security? +; + : load-from-device ( devname$ -- done? )
d# 16 0 +icon-xy show-dot @@ -730,7 +864,7 @@ else " minus" show-icon " new - " ?lease-debug - fwkey$ to pubkey$ + fwkey$ to pubkeylist$ img$ sig$ fw-valid? if img$ do-firmware-update then @@ -744,8 +878,9 @@ d# 16 0 +icon-xy show-dot " os" bundle-present? if " OS found - " ?lease-debug - oskey$ to pubkey$ + oskey$ to pubkeylist$ img$ sig$ sha-valid? if +\ ?disable-indexed-io img$ tuck load-base swap move !load-size show-unlock true exit @@ -794,7 +929,8 @@ ['] secure-load-ramdisk to load-ramdisk " init-program" $find if set-cmdline - execute show-going go + execute + show-going go then show-x security-failure
Modified: cpu/x86/pc/olpc/setwp.fth =================================================================== --- cpu/x86/pc/olpc/setwp.fth 2009-01-23 21:57:21 UTC (rev 1083) +++ cpu/x86/pc/olpc/setwp.fth 2009-01-28 00:17:24 UTC (rev 1084) @@ -173,3 +173,18 @@ r> r> h# ff fill ( ) put-mfg-data ; + +: delete-tag ( "name" -- ) safe-parse-word $delete-tag ; + +: add-tag-from-file ( "name" "filename" -- ) + safe-parse-word 2>r ( r: name$ ) + reading ( r: name$ ) + ifd @ fsize >r ( r: name$ len ) + r@ alloc-mem ( adr r: name$ len ) + dup r@ ifd @ fgets ( adr actual r: name$ len ) + ifd @ fclose ( adr actual r: name$ len ) + r@ <> abort" File read error" ( adr r: name$ len ) + r> 2dup 2r> ( data$ data$ name$ ) + $add-tag ( data$ ) + free-mem +;