1
0

Compare commits

...

5 Commits

Author SHA1 Message Date
034d6aacc4 tangc handle non-zero exit from jwe dec
Sometimes it exits non-zero but decrypts the file *anyway*. It only
does this on the device and I haven't been able to reproduce on build,
so this is a workaround until we find the root cause
2024-09-01 09:57:38 +01:00
e590c0ad3f secrets subscriber: add provider as dep to controlled service 2024-09-01 09:56:59 +01:00
14abdd9998 tang: notify on ready 2024-08-31 23:24:50 +01:00
6287b92000 fix bugs handling base64 padding 2024-08-31 22:43:25 +01:00
d2215d3e56 tangc popen retry on short read 2024-08-31 22:18:23 +01:00
4 changed files with 67 additions and 17 deletions

View File

@ -46,5 +46,6 @@ in service.overrideAttrs(o: {
buildInputs = (lim.orEmpty o.buildInputs) ++ buildInputs = (lim.orEmpty o.buildInputs) ++
optional (watched-service != null) watcher; optional (watched-service != null) watcher;
dependencies = (lim.orEmpty o.dependencies) ++ dependencies = (lim.orEmpty o.dependencies) ++
optional (watched-service != null) watcher; optional (watched-service != null) watcher ++
optional (watched-service != null) watched-service;
}) })

View File

@ -8,13 +8,17 @@ let
in longrun { in longrun {
inherit name; inherit name;
buildInputs = [ json-to-fstree ]; buildInputs = [ json-to-fstree ];
notification-fd = 10;
run = '' run = ''
set -e
statedir=/run/${name} statedir=/run/${name}
mkdir -m 0700 $statedir mkdir -p -m 0700 $statedir
( in_outputs ${name} ( in_outputs ${name}
while : ; do while : ; do
${tangc}/bin/tangc decrypt < ${path} > $statedir/input.json ${tangc}/bin/tangc decrypt < ${path} > $statedir/.input.json
mv $statedir/.input.json $statedir/input.json
${json-to-fstree}/bin/json-to-fstree file://$statedir/input.json . ${json-to-fstree}/bin/json-to-fstree file://$statedir/input.json .
echo ready >&10
sleep ${builtins.toString (interval * 60)} sleep ${builtins.toString (interval * 60)}
done done
) )

View File

@ -110,16 +110,32 @@
(. bs (bor (lshift (band a 3) 4) (rshift b 4))) (. bs (bor (lshift (band a 3) 4) (rshift b 4)))
(. bs (bor (lshift (band b 15) 2) (rshift c 6))) (. bs (bor (lshift (band b 15) 2) (rshift c 6)))
(. bs (band c 63)))))))] (. bs (band c 63)))))))]
(s:sub 1 (- (# s) pad)))) (.. (s:sub 1 (- (# s) pad))
(string.rep "=" pad))))
(fn base64-decode [input rindices] (fn base64-decode [input rindices]
;; take groups of 4 characters, reverse-look them up in base64-indices, ;; take groups of 4 characters, reverse-look them up in base64-indices,
;; convert to 24 bit number, ;; convert to 24 bit number,
;; convert to three characters ;; convert to three characters
(let [padding (if (= (string.sub input -2 -1) "==") -3
(= (string.sub input -1 -1) "=") -2 ;; things that might happen at the end of the string:
-1) ;; 1) if the input string length was n * 3, it will have been
input (string.sub (.. input "===") 1 (* (/ (# input) 4) 4))] ;; encoded as n * 4 base64 digits, no special handling required
;; 2) if the input string length was (n * 3) + 2, the last 16 bits
;; are encoded into 3 base64 digits which are followed by an '='
;; 3) if the input string length was (n * 3) + 1, the last 8 bits
;; are encoded into 2 base64 digits which are followed by '=='
;; 0) there is never an '===' padding, because an 8 bit byte
;; can never be encoded into a single 6 bit base64 digit
(let [input (.. input (string.rep "=" (% (- 4 (# input)) 4)))
pad-chars (# (or (string.match input "(=+)$") ""))
trim-index (case pad-chars
0 -1
1 -2
2 -3
3 (assert nil "3 pad bytes??"))]
(-> (->
(icollect [s (string.gmatch input "(....)")] (icollect [s (string.gmatch input "(....)")]
(let [(a b c d) (string.byte s 1 4) (let [(a b c d) (string.byte s 1 4)
@ -128,14 +144,12 @@
(lshift (ri c) 6) (lshift (ri c) 6)
(lshift (ri b) 12) (lshift (ri b) 12)
(lshift (ri a) 18))] (lshift (ri a) 18))]
(string.pack "bbb" (string.pack "bbb"
(rshift (band 0xff0000 n) 16) (rshift (band 0xff0000 n) 16)
(rshift (band 0x00ff00 n) 8) (rshift (band 0x00ff00 n) 8)
(band 0x0000ff n)))) (band 0x0000ff n))))
(table.concat "") (table.concat "")
(string.sub 1 padding) (string.sub 1 trim-index)
))) )))
(fn base64 [alphabet-des] (fn base64 [alphabet-des]
@ -149,8 +163,10 @@
:decode (fn [_ str] (base64-decode str ralphabet)) :decode (fn [_ str] (base64-decode str ralphabet))
})) }))
(fn base64url [str] (: (base64 :url) :encode str)) (fn base64url [str]
;; for backward-compatibility, this does not pad the encoded string
(let [encoded (: (base64 :url) :encode str)]
(pick-values 1 (string.gsub encoded "=+$" ""))))
(define-tests (define-tests
@ -164,7 +180,25 @@
(let [a (b64:decode "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms=")] (let [a (b64:decode "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms=")]
(assert (= a "Many hands make light work") (view a))) (assert (= a "Many hands make light work") (view a)))
(let [a (b64:encode "hello world")] (let [a (b64:encode "hello world")]
(assert (= a "aGVsbG8gd29ybGQ") a)))) (assert (= a "aGVsbG8gd29ybGQ=") a))
(fn check [plain enc]
(let [a (b64:encode plain)] (assert (= a enc) (.. "encode " a)))
(let [a (b64:decode enc)] (assert (= a plain) (.. "decode " a))))
(check "" "")
(check "f" "Zg==")
(check "fo" "Zm8=")
(check "foo" "Zm9v")
(check "foob" "Zm9vYg==")
(check "fooba" "Zm9vYmE=")
(check "foobar" "Zm9vYmFy")
(let [x (b64:decode "REtOdUtNS05BNEJWLXdfcUhtNU9YV2liOUxkX3RTdVJTQWVUR0dkWldBdVEyaURObDZ2b3pSbEJwMzlzOEltdkhWdmpzZmMiLCJ5IjoiQVlDY1QwOGZrNFZWZ2lZSVIxbkU4UlJGaGZOSGdBUEFzckRITmJtRGNfUGtWZmdDR0xTMTIweU5SNncwdjd5RUY4WDN1OGpvazhkU0pqN0hnWjZCZHAzcSJ9LCJraWQiOiJlalVDaXBCUE9BeDRWQ1dQdUtkVGlYNDNadW5XTDNjSWN6V1h1RVZyTVNFIn0")]
(assert (string.match x "}$") x))
))
;; doesn't work if the padding is missing ;; doesn't work if the padding is missing

View File

@ -18,6 +18,10 @@
(if (< written (# str)) (if (< written (# str))
(write-all fd (string.sub str (+ written 1) -1))))) (write-all fd (string.sub str (+ written 1) -1)))))
(fn read-all [fd]
(let [buf (ll.read fd)]
(if (> (# buf) 0) (.. buf (read-all fd)) buf)))
(fn jose [params inputstr] (fn jose [params inputstr]
(let [env (ll.environ) (let [env (ll.environ)
argv (doto params (table.insert 1 "jose")) argv (doto params (table.insert 1 "jose"))
@ -29,7 +33,7 @@
(ll.close in) (ll.close in)
(let [output (let [output
(accumulate [o "" (accumulate [o ""
buf #(match (ll.read out) "" nil s s)] buf #(match (read-all out) "" nil s s)]
(.. o buf))] (.. o buf))]
(values (exited pid) output)))) (values (exited pid) output))))
@ -71,8 +75,15 @@
(.. (json.encode clt) " " (json.encode eph)))) (.. (json.encode clt) " " (json.encode eph))))
(fn jwe-dec [jwk ph undigested] (fn jwe-dec [jwk ph undigested]
(josep! ["jwe" "dec" "-k-" "-i-"] ;; sometimes jose jwe dec decrypts the file and exits
(.. (json.encode jwk) ph "." undigested))) ;; non-zero anyway. FIXME find out why
(let [inputstr (.. (json.encode jwk) ph "." undigested)
(exitcode out) (jose ["jwe" "dec" "-k-" "-i-"] inputstr)]
(if (> exitcode 0)
(: io.stderr :write (%% "jose jwe dec exited %d\n" exitcode)))
(if (not (= out ""))
out
(error (%% "jose jwe dec produced no output, exited %d" exitcode)))))
(fn parse-jwe [jwe] (fn parse-jwe [jwe]
(assert (= jwe.clevis.pin "tang") "invalid clevis.pin") (assert (= jwe.clevis.pin "tang") "invalid clevis.pin")