oficina / home Public

Clone
git clone https://amadan.net/oficina/home

Plain git — no account needed to clone.

Download

Download this file

1package operator
2
3import (
4 "encoding/base64"
5 "encoding/hex"
6 "time"
7
8 family "amadan.net/rastrillo/rastrillo/crypto"
9)
10
11// Private v2 wire types cannot enter the v1 engine or journal. The future
12// verified adapter must also match these pins against the embedded catalog.
13type schemaAuthorizationV2 struct {
14 Authorization
15 SchemaProfile string `json:"schema_profile"`
16 SchemaManifestDigest string `json:"schema_manifest_digest"`
17}
18type schemaInspectV2 struct {
19 InspectChallenge
20 SchemaProfile string `json:"schema_profile"`
21 SchemaManifestDigest string `json:"schema_manifest_digest"`
22}
23type schemaVerifierV2 struct {
24 base *Verifier
25 profile, manifestDigest string
26}
27type schemaRequestV2 struct {
28 authorization schemaAuthorizationV2
29 input []byte
30 head string
31}
32
33func validSchemaPinV2(role, profile, manifestDigest string) bool {
34 sum, err := hex.DecodeString(manifestDigest)
35 if err != nil || len(sum) != 32 || hex.EncodeToString(sum) != manifestDigest {
36 return false
37 }
38 return role == "credential" && profile == "credential-current-v1" ||
39 role == "directory" && (profile == "directory-current-v1" || profile == "directory-historical-empty-v1")
40}
41func newSchemaVerifierV2(p Pins, profile, manifestDigest string) (*schemaVerifierV2, error) {
42 if !validSchemaPinV2(p.Role, profile, manifestDigest) {
43 return nil, ErrRefused
44 }
45 base, err := NewVerifier(p)
46 if err != nil {
47 return nil, err
48 }
49 return &schemaVerifierV2{base, profile, manifestDigest}, nil
50}
51func validSchemaAuthorizationV2(a schemaAuthorizationV2) bool {
52 if a.Version != 2 || !validSchemaPinV2(a.Role, a.SchemaProfile, a.SchemaManifestDigest) {
53 return false
54 }
55 base := a.Authorization
56 base.Version = 1
57 return base.valid()
58}
59func validSchemaInspectV2(c schemaInspectV2) bool {
60 if c.Version != 2 || !validSchemaPinV2(c.Role, c.SchemaProfile, c.SchemaManifestDigest) {
61 return false
62 }
63 base := c.InspectChallenge
64 base.Version = 1
65 return base.valid()
66}
67func signSchemaRequestV2(k *family.Keypair, a schemaAuthorizationV2, input any) ([]byte, error) {
68 if !signingKey(k) {
69 return nil, ErrRefused
70 }
71 b, err := encode(input)
72 if err != nil || len(b) > InputLimit {
73 return nil, ErrRefused
74 }
75 a.InputDigest = digest(b)
76 if !validSchemaAuthorizationV2(a) {
77 return nil, ErrRefused
78 }
79 payload, err := encode(a)
80 if err != nil {
81 return nil, err
82 }
83 sig, err := family.Sign(k, InputContext, payload)
84 if err != nil {
85 return nil, ErrUnavailable
86 }
87 env, err := encode(envelope{1, keyID(k.SignPub()), base64.RawURLEncoding.EncodeToString(payload), base64.RawURLEncoding.EncodeToString(sig)})
88 if err != nil || len(env) > AuthorizationLimit {
89 return nil, ErrRefused
90 }
91 out, err := encode(wrapper{2, env, b})
92 if err != nil || len(out) > BodyLimit {
93 return nil, ErrRefused
94 }
95 return out, nil
96}
97func verifySchemaRequestV2(v *schemaVerifierV2, raw []byte) (schemaRequestV2, error) {
98 fail := func() (schemaRequestV2, error) { return schemaRequestV2{}, ErrRefused }
99 if v == nil || v.base == nil || len(raw) == 0 || len(raw) > BodyLimit {
100 return fail()
101 }
102 var w wrapper
103 if strictCanonical(raw, &w) != nil || w.Version != 2 || len(w.Authorization) == 0 || len(w.Authorization) > AuthorizationLimit || len(w.Input) == 0 || len(w.Input) > InputLimit {
104 return fail()
105 }
106 var env envelope
107 if strictCanonical(w.Authorization, &env) != nil || env.Version != 1 || env.KeyID != v.base.kid {
108 return fail()
109 }
110 payload, ok := canonical(env.Payload, -1)
111 sig, ok2 := canonical(env.Signature, 64)
112 if !ok || !ok2 || len(payload) > AuthorizationLimit || !family.Verify(v.base.key, InputContext, payload, sig) {
113 return fail()
114 }
115 var a schemaAuthorizationV2
116 if strictCanonical(payload, &a) != nil || !validSchemaAuthorizationV2(a) {
117 return fail()
118 }
119 p := v.base.pins
120 if !v.base.actions[a.Action] || a.Role != p.Role || a.Origin != p.Origin || a.Installation != p.Installation || a.Registry != p.Registry || a.Device != p.Device || a.InputDigest != digest(w.Input) || a.SchemaProfile != v.profile || a.SchemaManifestDigest != v.manifestDigest {
121 return fail()
122 }
123 return schemaRequestV2{a, append([]byte(nil), w.Input...), digest(w.Authorization)}, nil
124}
125func signSchemaInspectV2(k *family.Keypair, c schemaInspectV2) ([]byte, error) {
126 if !signingKey(k) || !validSchemaInspectV2(c) {
127 return nil, ErrRefused
128 }
129 payload, err := encode(c)
130 if err != nil {
131 return nil, err
132 }
133 sig, err := family.Sign(k, InspectContext, payload)
134 if err != nil {
135 return nil, ErrUnavailable
136 }
137 return encode(envelope{1, keyID(k.SignPub()), base64.RawURLEncoding.EncodeToString(payload), base64.RawURLEncoding.EncodeToString(sig)})
138}
139func verifySchemaInspectV2(v *schemaVerifierV2, raw []byte, now time.Time) (schemaInspectV2, error) {
140 fail := func() (schemaInspectV2, error) { return schemaInspectV2{}, ErrRefused }
141 if v == nil || v.base == nil || len(raw) == 0 || len(raw) > AuthorizationLimit {
142 return fail()
143 }
144 var env envelope
145 if strictCanonical(raw, &env) != nil || env.Version != 1 || env.KeyID != v.base.kid {
146 return fail()
147 }
148 payload, ok := canonical(env.Payload, -1)
149 sig, ok2 := canonical(env.Signature, 64)
150 if !ok || !ok2 || len(payload) > AuthorizationLimit || !family.Verify(v.base.key, InspectContext, payload, sig) {
151 return fail()
152 }
153 var c schemaInspectV2
154 if strictCanonical(payload, &c) != nil || !validSchemaInspectV2(c) {
155 return fail()
156 }
157 p := v.base.pins
158 if !v.base.actions["directory.inspect"] || c.Role != p.Role || c.Origin != p.Origin || c.Installation != p.Installation || c.Registry != p.Registry || c.Device != p.Device || c.SchemaProfile != v.profile || c.SchemaManifestDigest != v.manifestDigest || c.Issued > now.Unix() || c.Expires <= now.Unix() {
159 return fail()
160 }
161 return c, nil
162}
163