-
Notifications
You must be signed in to change notification settings - Fork 62
/
team_hidden.iced
177 lines (156 loc) · 5.02 KB
/
team_hidden.iced
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
{Base} = require './sig3'
{constants} = require './constants'
parse = require './parse3'
{EncKeyManager, KeyManager} = require('kbpgp').kb
{make_esc} = require 'iced-error'
schema = require './schema3'
{pack,unpack} = require 'purepack'
#------------------
exports.TeamBase = class TeamBase extends Base
constructor : (args) ->
@team = args.team
super args
_v_encode_inner : ({json}) ->
obj = { i : Buffer.from(@team.id, 'hex') }
obj.m = !!@team.is_implicit
obj.p = !!@team.is_public
if @team.admin?
obj.a = {
i : @team.admin.id
s : @team.admin.seqno
t : @team.admin.chain_type
}
json.t = obj
_v_extend_schema : (schm) ->
schm.set_key "t", schema.dict({
a : schema.dict({
i : schema.binary(16).name("team_id")
s : schema.seqno().name("seqno")
t : schema.chain_type().name("chain_type") }).optional().name("implicit_admin")
i : schema.binary(16).name("team_id")
m : schema.bool().optional().name("is_implicit")
p : schema.bool().optional().name("is_public") }).name('team')
_v_decode_inner : ({json}, cb) ->
@team = {
id : json.t.i
is_public : !!json.t.p
is_implicit : !!json.t.m
}
if json.t.a?
@team.admin = {
id : json.t.a.i
seqno : json.t.a.s
chain_type : json.t.a.t
}
cb null
to_v2_team_obj : () ->
ret = {
id : @team.id.toString('hex')
is_implicit : @team.is_implicit
is_public : @team.is_public
}
if @team.admin?
ret.admin = {
team_id : @team.admin.id.toString('hex')
seqno : @team.admin.seqno
seq_type : @team.admin.chain_type
}
return ret
#------------------
exports.RotateKey = class RotateKey extends TeamBase
constructor : (args) ->
@per_team_keys = args.per_team_keys
super args
_v_encode_inner : ({json}) ->
super { json }
keys = for k in @per_team_keys
{
a : constants.appkey_derivation_version.xor
c : k.seed_check
e : k.enc_km.key.ekid()
g : k.generation
r : null
s : k.sig_km.key.ekid()
t : k.ptk_type
}
json.b = { k : keys }
_v_extend_schema : (schm) ->
super schm
elem = schema.dict({
a : schema.value(constants.appkey_derivation_version.xor).name("appkey_derivation_version")
c : schema.dict({
h : schema.binary(32).name("hash")
v : schema.value(1).name("version") }).name("seed_check")
e : schema.enc_kid().name("encryption_kid")
g : schema.seqno().name("generation")
r : schema.binary(64).name("reverse_sig")
s : schema.kid().name("signing_kid")
t : schema.ptk_type().name("ptk_type")
}).name("key")
schm.set_key "b", schema.dict({
k : schema.array(elem).name("keys")
}).name("body")
_decode_key : ({key}, cb) ->
esc = make_esc cb
ret = {
generation : key.g
appkey_derivation_version : key.a
reverse_sig : key.r
ptk_type : key.t
}
await EncKeyManager.import_public { raw : key.e }, esc defer ret.enc_km
await KeyManager.import_public { raw : key.s }, esc defer ret.sig_km
cb null, ret
_v_decode_inner : ({json}, cb) ->
esc = make_esc cb
await super { json }, esc defer()
@per_team_keys = []
seen = {}
for key in json.b.k
await @_decode_key { key }, esc defer ptk
if seen[ptk.ptk_type]
return cb new Error "Repeated PTK type #{ptk.ptk_type} not allowed"
seen[ptk.ptk_type] = true
@per_team_keys.push ptk
cb null
_v_reverse_sign : ({inner, outer}, cb) ->
esc = make_esc cb
for k,i in @per_team_keys
await @_sign { sig_eng : k.sig_km.make_sig_eng(), outer }, esc defer sig
inner.b.k[i].r = sig
outer = @_generate_outer { inner }
cb null, { inner, outer }
_v_verify_reverse_sig : ({inner, outer_obj}, cb) ->
esc = make_esc cb
reverse_sigs = []
reverse_sigs = (k.r for k in inner.b.k)
inner_hash = outer_obj.inner_hash
for k, i in inner.b.k by -1
sig = k.r
k.r = null
outer_obj.inner_hash = @_hash inner
outer = outer_obj.encode()
payload = pack outer
await @per_team_keys[i].sig_km.verify_raw { prefix : @_prefix(), payload, sig }, esc defer()
for s, i in reverse_sigs
inner.b.k[i].r = s
cb null
_v_link_type_v3 : () -> constants.sig_types_v3.team.rotate_key
_v_chain_type_v3 : -> constants.seq_types.TEAM_HIDDEN
_v_assert_is_v2_legacy : () ->
return err if err?
if @per_team_keys.length isnt 1
return new Error "need exactly one PTK"
if @per_team_keys[0].ptk_type isnt constants.ptk_types.reader
return new Error "need a reader PTK (no current support for bot or admin keys)"
null
to_v2_team_obj : () ->
ret = super()
k = @per_team_keys[0]
ret.per_team_key =
encryption_kid : k.enc_km.key.ekid().toString('hex')
signing_kid : k.sig_km.key.ekid().toString('hex')
generation : k.generation
reverse_sig : k.reverse_sig.toString('base64')
return ret
#------------------