miniroon

Simplistic macaroon-based authorization for Unix systems
git clone https://ccx.te2000.cz/git/miniroon
Log | Files | Refs | README

gen-miniroon.py (2314B)


      1 #!/usr/bin/env python3
      2 import argparse
      3 import base64
      4 import hmac
      5 import json
      6 import os
      7 import sys
      8 
      9 
     10 class NetString(bytes):
     11     @classmethod
     12     def from_any(cls, data):
     13         if isinstance(data, NetString):
     14             return cls(data)
     15         if isinstance(data, bytes):
     16             return cls(to_ns(data))
     17         if isinstance(data, str):
     18             return cls(to_ns(data.encode('ascii')))
     19         assert not isinstance(data, dict)
     20         return cls(to_ns(to_ns_list(data)))
     21 
     22 
     23 def to_ns(b):
     24     assert isinstance(b, bytes)
     25     return NetString(b'%d:%s,' % (len(b), b))
     26 
     27 
     28 def to_ns_list(data):
     29     assert not isinstance(data, (dict, bytes, str))
     30     return b''.join(NetString.from_any(i) for i in data)
     31 
     32 
     33 def miniroon_hmac(key, msg):
     34     assert len(key) == 32
     35     print('miniroon_hmac%r' % ((key, msg),), file=sys.stderr)
     36     #return hmac.digest(key, msg, 'blake2s')
     37     return hmac.digest(key, msg, 'sha256')
     38 
     39 
     40 def make_miniroon(name, action='invoke-once', secret=b'\0'*32, caveats=(), version='capv0', unwrap=False):
     41     hdr = b''.join(NetString.from_any(i) for i in (version, name, action))
     42     caveats_ns = [to_ns_list(c) for c in caveats]
     43     sig = miniroon_hmac(secret, hdr)
     44     for c in caveats_ns:
     45         sig = miniroon_hmac(sig, c)
     46     if unwrap:
     47         return b''.join(map(NetString.from_any, (hdr, caveats_ns, sig)))
     48     else:
     49         return NetString.from_any([hdr, caveats_ns, sig])
     50 
     51 
     52 def main_old():
     53     import os
     54     # os.write(1, make_miniroon(name='ccx'))
     55     os.write(1, make_miniroon(name='ccx', caveats=[
     56         ('env-is', 'var1', 'hello'),
     57         ('env-absent', 'var2'),
     58         ('env-glob', 'var3', '_*'),
     59         # ('x-glob', 'var3', '_*'),
     60         ('env-is', 'var3', '_hello'),
     61     ]))
     62 
     63 
     64 argument_parser = argparse.ArgumentParser()
     65 argument_parser.add_argument('--unwrap', action='store_true', default=False)
     66 argument_parser.add_argument('json_in', type=argparse.FileType(mode='r'), nargs="?", default=sys.stdin)
     67 
     68 
     69 def main():
     70     args = argument_parser.parse_args()
     71     data = json.load(args.json_in)
     72     data['unwrap'] = args.unwrap
     73     assert isinstance(data, dict)
     74     if 'secret_b64' in data:
     75         assert 'secret' not in data
     76         data['secret'] = base64.b64decode(data.pop('secret_b64'))
     77     os.write(1, make_miniroon(**data))
     78 
     79 
     80 if __name__ == '__main__':
     81     main()