From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 21848 invoked from network); 1 Sep 2021 10:21:23 -0000 Received: from 4ess.inri.net (216.126.196.42) by inbox.vuxu.org with ESMTPUTF8; 1 Sep 2021 10:21:23 -0000 Received: from mimir.eigenstate.org ([206.124.132.107]) by 4ess; Tue Aug 31 21:37:40 -0400 2021 Received: from abbatoir.myfiosgateway.com (pool-74-108-56-225.nycmny.fios.verizon.net [74.108.56.225]) by mimir.eigenstate.org (OpenSMTPD) with ESMTPSA id 7e89503d (TLSv1.2:ECDHE-RSA-AES256-SHA:256:NO) for <9front@9front.org>; Tue, 31 Aug 2021 18:37:30 -0700 (PDT) Message-ID: <9FC46F3B1F0981A3E325246D34DB1545@eigenstate.org> To: 9front@9front.org Date: Tue, 31 Aug 2021 21:37:28 -0400 From: ori@eigenstate.org MIME-Version: 1.0 Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: progressive open-source factory hosting HTTP cloud CSS-based optimizer Subject: [9front] ipso: read keys from stdin Reply-To: 9front@9front.org Precedence: bulk It's useful to generate keys programatically and put them into factotum. Things like SSH keys or certificate signing requests could stand to go directly to secstore. For example, the ssh example in rsa(8) could be rewritten from: auth/rsagen -t 'service=ssh' >key auth/rsa2ssh key | ssh unix 'cat >>.ssh/authorized_keys' cat key >/mnt/factotum/ctl to: auth/rsagen -t 'service=ssh' | \ tee >{auth/rsa2ssh | ssh unix 'cat >>.ssh/authorized_keys}' | \ >/mnt/factotum/ctl or the csr for acmed could be generated as: auth/rsagen -t 'service=acme role=sign hash=sha256 acct=me@example.org' \ | tee >{auth/rsa2jwk \ >/sys/lib/tls/acmed/me@example.org.pub} | ipso -r -l factotum As a result, I started hacking in support for reading keys directly from stdin to ipso, which quickly turned into a partial rewrite. 2 major changes, and a bit of code shuffling: - we look for changes to files by qid instead of by timestamp - we keep the files in a directory and their metadata elsewhere I also took the opportunity to improve the manpage a bit, though I didn't document the '-f', '-l', and '-e' flags: I'm not sure where they're useful. diff 49b5319f761e2de848d35361a507a5af8b6eb1ed uncommitted --- a//rc/bin/ipso +++ b//rc/bin/ipso @@ -1,8 +1,9 @@ #!/bin/rc + # ipso - edit secstore files, reload factotum keys if(! ~ $service terminal && ! ~ $user `{ ls -ld /mnt/factotum/ctl | awk '{print $4}' }){ - echo >[1=2] ipso should be run only on the terminal + msg ipso should be run only on the terminal exit terminal } @@ -9,112 +10,93 @@ rfork e path=(/bin) home=(/tmp) -editor = (acme -c1) -name = secstore -get = secstoreget -put = secstoreput -edit = no -load = no -flush = no +pass=/tmp/_password +editor=(acme -c1) +edexp=`{grep '^editor=' /mnt/plumb/rules >[2]/dev/null} +if(~ $#edexp 1) + eval $edexp +nl=' +' -fn secstoreget{ - auth/secstore -i -g $1 <_password -} +args='[file...]' +flagsfile='s:usesam, a:useaescbc, f:flush, e:edit, l:load, r:readin' +if(! eval `''{aux/getflags $*}) + exec aux/usage -fn secstoreput{ - auth/secstore -i -p $1 <_password +fn msg{ + echo $* >[1=2] } -fn aesget{ - if(! ~ $1 /*){ - echo >[1=2] ipso: aescbc requires fully qualified pathname - exit usage +if(~ $#useaescbc 0){ + name=secstore + fn get{ + auth/secstore -i -g $1 <$pass } - auth/aescbc -i -d < $1 > `{basename $1} <[3] _password -} + fn put{ + auth/secstore -i -p $1 <$pass + } -fn aesput{ - auth/aescbc -i -e > $1 < `{basename $1} <[3] _password } - -fn editedfiles{ - if(~ $get aesget){ - for(i in $files) - if(ls -tr | sed '1,/^_timestamp$/d' | grep -s '^'^`{basename $i}^'$') - echo $i +if not { + name=aescbc + if(~ $#* 0){ + msg ipso: must specify a fully qualified file name for aescbc '(-a)' + exit usage } - if not - ls -tr | sed '1,/^_timestamp$/d' -} + fn get{ + if(! ~ $1 /*){ + msg aescbc requires fully qualified pathname + exit usage + } + auth/aescbc -i -d < $1 > `{basename $1} <[3] $pass + } -edexp=`{grep '^editor=' /mnt/plumb/rules >[2]/dev/null} -if(~ $#edexp 1) - eval $edexp - -while(~ $1 -*){ - switch($1){ - case -s - editor = sam - case -a - name = aescbc - get = aesget - put = aesput - case -f - flush = yes - case -e - edit = yes - case -l - load = yes - case * - echo >[2=1] 'usage: ipso [-a -f -e -l] [-s] [file ...]' - exit usage + fn put{ + auth/aescbc -i -e > $1 < `{basename $1} <[3] $pass } - shift } -if(~ $flush no && ~ $edit no && ~ $load no){ - load = yes - edit = yes - flush = yes +fn edited { + for(f in $files) + if(! ~ `{walk -eq $f} `{cat ../qids/$f}) + echo $f } -if(~ $flush yes && ~ $edit no && ~ $load no){ - echo flushing old keys - echo delkey > /mnt/factotum/ctl - exit 0 -} - -if(~ $get aesget && ~ $#* 0){ - echo >[2=1] ipso: must specify a fully qualified file name for aescbc '(-a)' - exit usage -} - rfork ne ramfs -p >[2] /dev/null # silence 'i/o on hungup channel' message at exit unmount /mnt/plumb bind -c /tmp /srv -builtin cd /tmp +mkdir /tmp/qids +mkdir /tmp/data +builtin cd /tmp/data -if ( ~ $edit yes ) echo ' +if(~ $#flush 0 && ~ $#edit 0 && ~ $#load 0 && ~ $#readin 0){ + load = 1 + edit = 1 + flush = 1 + readin = () +} + +if ( ~ $edit 1 ) + msg ' Warning: The editor will display the secret contents of your '$name' files in the clear. ' + # get password and remember it { echo rawon echo -n $name password: >/dev/cons - read > _password + read > $pass echo > /dev/cons } /dev/consctl # get list of files if(~ $#* 0){ - if(! auth/secstore -G . -i < _password > _listing){ - echo 'secstore read failed - bad password?' - sleep 2 + if(! files=`{auth/secstore -G . -i < $pass | sed 's/[ ]+.*//'}){ + msg 'secstore read failed - bad password?' exit password } - files=`{sed 's/[ ]+.*//' _listing} } if not files = $* @@ -121,43 +103,49 @@ # copy the files to local ramfs for(i in $files){ - if(! $get $i){ - echo $name ' read failed - bad password?' - sleep 2 + if(! get $i){ + msg $name ' read failed - bad password?' exit password } + walk -eq $i > ../qids/$i } -sleep 2; date > _timestamp # so we can find which files have been edited. # edit the files -if(~ $edit yes) $editor `{for(i in $files) basename $i} -if(~ $flush yes ){ - echo flushing old keys +if(~ $readin 1) { + if(! ~ $#files 1){ + msg $name ': ambiguous file to append' + exit toomany + } + cat >>$files +} +if not if(~ $edit 1) + $editor `{for(i in $files) basename $i} +if(~ $flush 1 ){ + msg flushing old keys echo delkey > /mnt/factotum/ctl } -if(~ $load yes){ - echo loading factotum keys - if (~ factotum $files) read -m < factotum > /mnt/factotum/ctl +if(~ $load 1){ + msg loading factotum keys + if (~ factotum $files) + read -m < factotum > /mnt/factotum/ctl } # copy the files back -for(i in `{editedfiles}){ - echo -n copy ''''`{basename $i}^'''' back?' [y/n/x]' - switch(`{read}){ +for(i in `{edited}){ + msg -n copy ''''`{basename $i}^'''' back?' [y/n/x] ' + switch(`{read /dev/cons}){ case [yY]* - if(! $put $i){ - echo $name ' read failed - bad password?' + if(! put $i){ + msg $name ' read failed - bad password?' sleep 2 exit password } - echo ''''$i'''' copied to $name + msg ''''$i'''' copied to $name if(~ $i factotum) read -m < $i > /mnt/factotum/ctl case [xXqQ]* exit case [nN]* * - echo ''''$i'''' skipped + msg ''''$i'''' skipped } } - -exit '' --- a//sys/man/1/secstore +++ b//sys/man/1/secstore @@ -36,7 +36,7 @@ .PP .B ipso [ -.B -a -e -l -f -s +.B -[asr] ] [ .I file \&... @@ -53,8 +53,9 @@ .B -c prompts for a password change. .PP -Option -.B -g +It accepts the following options: +.TP +.B -g, -G retrieves a file to the local directory; option .B -G @@ -65,14 +66,12 @@ .L \&. will send to standard output a list of remote files with dates, lengths and SHA1 hashes. -.PP -Option +.TP .B -i says that the password should be read from standard input instead of from .BR /dev/cons . -.PP -Option +.TP .B -n says that the password should be read from NVRAM (see @@ -79,16 +78,13 @@ .IR authsrv (2)) instead of from .BR /dev/cons . -.PP -Option +.TP .B -p stores a file on the secstore. -.PP -Option +.TP .B -r removes a file from the secstore. -.PP -Option +.TP .B -s sets the dial string of the .IR secstore (8) @@ -102,21 +98,19 @@ .IR secstore (1) will attempt to dial .BR tcp!$auth!secstore . -.PP -Option +.TP .B -u access the secure-store files belonging to .IR user . -.PP -Option +.TP .B -v produces more verbose output, in particular providing a few bits of feedback to help the user detect mistyping. -.PP +.IP For example, to add a secret to the file read by .IR factotum (4) at startup, open a new window, type -.LP +.IP .EX % ramfs -p; cd /tmp % auth/secstore -g factotum @@ -126,7 +120,7 @@ secstore password: % read -m factotum > /mnt/factotum/ctl .EE -.LP +.IP and delete the window. The first line creates an ephemeral memory-resident workspace, invisible to others and automatically removed when the window is deleted. @@ -176,18 +170,10 @@ .I ipso will just perform only the requested operations, i.e., edit, flush, and/or load. -.PP -The -.B -s -option of -.I ipso -invokes -.IR sam (1) -as the editor insted of -.BR acme ; -the +Ipso accepts the following options: +.TP .B -a -option provides a similar service for files encrypted by +causes acme to act on files encrypted by .I aescbc .RI ( q.v. ). With the @@ -200,6 +186,28 @@ Also with .BR -a , newly created files are ignored. +.TP +.B -r +reads a key specification from stdin, adding it to +the file managed by factotum. +When +.B -r +is passed, only one file must be edited at once. +.TP +.B -s +invokes +.IR sam (1) +as the editor. +If +.B -s +is not specified, then the editor is inferred from +the contents of +.IR /mnt/plumb/rules , +falling back to +.IR acme (1) +if there is no +.I editor= +line present. .PP .I Aescbc encrypts (under