Line data Source code
1 : #include "fd_keyguard.h"
2 : #include "fd_keyguard_client.h"
3 : #include "../bundle/fd_bundle_crank_constants.h"
4 : #include "../../waltz/tls/fd_tls.h"
5 :
6 : struct fd_keyguard_sign_req {
7 : fd_keyguard_authority_t * authority;
8 : };
9 :
10 : typedef struct fd_keyguard_sign_req fd_keyguard_sign_req_t;
11 :
12 : static int
13 : fd_keyguard_authorize_vote_txn( fd_keyguard_authority_t const * authority,
14 : uchar const * data,
15 : ulong sz,
16 0 : int sign_type ) {
17 : /* FIXME Add vote transaction authorization here */
18 0 : (void)authority; (void)data; (void)sz; (void)sign_type;
19 0 : return 1;
20 0 : }
21 :
22 : static int
23 : fd_keyguard_authorize_gossip( fd_keyguard_authority_t const * authority,
24 : uchar const * data,
25 : ulong sz,
26 0 : int sign_type ) {
27 : /* FIXME Add gossip message authorization here */
28 0 : (void)authority; (void)data; (void)sz; (void)sign_type;
29 0 : return 1;
30 0 : }
31 :
32 : static int
33 : fd_keyguard_authorize_bundle_crank_txn( fd_keyguard_authority_t const * authority,
34 : uchar const * data,
35 : ulong sz,
36 0 : int sign_type ) {
37 0 : static const uchar disc1[ 8 ] = { FD_BUNDLE_CRANK_DISC_INIT_TIP_DISTR };
38 0 : static const uchar disc2[ 8 ] = { FD_BUNDLE_CRANK_DISC_CHANGE_TIP_RCV };
39 0 : static const uchar disc3[ 8 ] = { FD_BUNDLE_CRANK_DISC_CHANGE_BLK_BLD };
40 :
41 0 : if( sign_type != FD_KEYGUARD_SIGN_TYPE_ED25519 ) return 0;
42 :
43 0 : (void)authority;
44 : /* TODO: we can check a lot more bytes */
45 0 : switch( sz ) {
46 0 : case (FD_BUNDLE_CRANK_2_SZ-65UL):
47 0 : return fd_memeq( data+FD_BUNDLE_CRANK_2_IX1_DISC_OFF-65UL, disc2, 8UL ) &&
48 0 : fd_memeq( data+FD_BUNDLE_CRANK_2_IX2_DISC_OFF-65UL, disc3, 8UL );
49 0 : case (FD_BUNDLE_CRANK_3_SZ-65UL):
50 0 : return fd_memeq( data+FD_BUNDLE_CRANK_3_IX1_DISC_OFF-65UL, disc1, 8UL ) &&
51 0 : fd_memeq( data+FD_BUNDLE_CRANK_3_IX2_DISC_OFF-65UL, disc2, 8UL ) &&
52 0 : fd_memeq( data+FD_BUNDLE_CRANK_3_IX3_DISC_OFF-65UL, disc3, 8UL );
53 0 : default:
54 0 : return 0;
55 0 : }
56 0 : }
57 :
58 : static int
59 : fd_keyguard_authorize_ping( fd_keyguard_authority_t const * authority,
60 : uchar const * data,
61 : ulong sz,
62 0 : int sign_type ) {
63 0 : (void)authority;
64 0 : if( sign_type != FD_KEYGUARD_SIGN_TYPE_SHA256_ED25519 ) return 0;
65 0 : if( sz != 48 ) return 0;
66 0 : if( 0!=memcmp( data, "SOLANA_PING_PONG", 16 ) ) return 0;
67 0 : return 1;
68 0 : }
69 :
70 : static int
71 : fd_keyguard_authorize_gossip_prune( fd_keyguard_authority_t const * authority,
72 : uchar const * data,
73 : ulong sz,
74 0 : int sign_type ) {
75 0 : if( FD_UNLIKELY( sign_type != FD_KEYGUARD_SIGN_TYPE_ED25519 ) ) return 0;
76 : /* Prune messages always begin with the node's pubkey */
77 0 : if( sz<40UL ) return 0;
78 0 : if( 0!=memcmp( authority->identity_pubkey, data, 32 ) ) return 0;
79 0 : return 1;
80 0 : }
81 :
82 : static int
83 : fd_keyguard_authorize_repair( fd_keyguard_authority_t const * authority,
84 : uchar const * data,
85 : ulong sz,
86 0 : int sign_type ) {
87 :
88 0 : if( sign_type != FD_KEYGUARD_SIGN_TYPE_ED25519 ) return 0;
89 0 : if( sz<80 ) return 0;
90 :
91 0 : uint discriminant = fd_uint_load_4( data );
92 0 : uchar const * sender = data+4;
93 :
94 0 : if( discriminant< 8 ) return 0; /* window_index is min ID */
95 0 : if( discriminant>11 ) return 0; /* ancestor_hashes is max ID */
96 :
97 0 : if( 0!=memcmp( authority->identity_pubkey, sender, 32 ) ) return 0;
98 :
99 0 : return 1;
100 0 : }
101 :
102 : static int
103 : fd_keyguard_authorize_tls_cv( fd_keyguard_authority_t const * authority FD_PARAM_UNUSED,
104 : uchar const * data,
105 : ulong sz,
106 0 : int sign_type ) {
107 0 : if( FD_UNLIKELY( sign_type != FD_KEYGUARD_SIGN_TYPE_ED25519 ) ) return 0;
108 0 : if( FD_UNLIKELY( sz != 130 ) ) return 0;
109 :
110 : /* validate client prefix against fd_tls */
111 0 : return fd_memeq( fd_tls13_cli_sign_prefix, data, sizeof(fd_tls13_cli_sign_prefix) );
112 0 : }
113 :
114 : int
115 : fd_keyguard_payload_authorize( fd_keyguard_authority_t const * authority,
116 : uchar const * data,
117 : ulong sz,
118 : int role,
119 0 : int sign_type ) {
120 :
121 0 : if( sz > FD_KEYGUARD_SIGN_REQ_MTU ) {
122 0 : FD_LOG_WARNING(( "oversz signing request (role=%d sz=%lu)", role, sz ));
123 0 : return 0;
124 0 : }
125 :
126 : /* Identify payload type */
127 :
128 0 : ulong payload_mask = fd_keyguard_payload_match( data, sz, sign_type );
129 0 : int match_cnt = fd_ulong_popcnt( payload_mask );
130 0 : if( FD_UNLIKELY( payload_mask==0UL ) ) {
131 0 : FD_LOG_WARNING(( "unrecognized payload type (role=%#x)", (uint)role ));
132 0 : }
133 :
134 0 : int is_ambiguous = match_cnt != 1;
135 :
136 : /* We know that gossip, gossip prune, and repair messages are
137 : ambiguous, so allow mismatches here. */
138 0 : int is_gossip_repair =
139 0 : 0==( payload_mask &
140 0 : (~( FD_KEYGUARD_PAYLOAD_GOSSIP |
141 0 : FD_KEYGUARD_PAYLOAD_REPAIR |
142 0 : FD_KEYGUARD_PAYLOAD_PRUNE ) ) );
143 :
144 0 : if( FD_UNLIKELY( is_ambiguous && !is_gossip_repair ) ) {
145 0 : FD_LOG_WARNING(( "ambiguous payload type (role=%#x mask=%#lx)", (uint)role, payload_mask ));
146 0 : }
147 :
148 : /* Authorize each role */
149 :
150 0 : switch( role ) {
151 :
152 0 : case FD_KEYGUARD_ROLE_SEND: {
153 0 : int txn_ok = (!!( payload_mask & FD_KEYGUARD_PAYLOAD_TXN )) &&
154 0 : fd_keyguard_authorize_vote_txn( authority, data, sz, sign_type );
155 0 : int tls_ok = (!!( payload_mask & FD_KEYGUARD_PAYLOAD_TLS_CV )) &&
156 0 : fd_keyguard_authorize_tls_cv( authority, data, sz, sign_type );
157 0 : if( FD_UNLIKELY( !txn_ok && !tls_ok ) ) {
158 0 : FD_LOG_WARNING(( "unauthorized payload type for send (mask=%#lx)", payload_mask ));
159 0 : return 0;
160 0 : }
161 0 : return 1;
162 0 : }
163 :
164 0 : case FD_KEYGUARD_ROLE_GOSSIP: {
165 0 : int ping_ok = (!!( payload_mask & FD_KEYGUARD_PAYLOAD_PING )) &&
166 0 : fd_keyguard_authorize_ping( authority, data, sz, sign_type );
167 0 : int prune_ok = (!!( payload_mask & FD_KEYGUARD_PAYLOAD_PRUNE )) &&
168 0 : fd_keyguard_authorize_gossip_prune( authority, data, sz, sign_type );
169 0 : int gossip_ok = (!!( payload_mask & FD_KEYGUARD_PAYLOAD_GOSSIP )) &&
170 0 : fd_keyguard_authorize_gossip( authority, data, sz, sign_type );
171 0 : if( FD_UNLIKELY( !ping_ok && !prune_ok && !gossip_ok ) ) {
172 0 : FD_LOG_WARNING(( "unauthorized payload type for gossip (mask=%#lx)", payload_mask ));
173 0 : return 0;
174 0 : }
175 0 : return 1;
176 0 : }
177 :
178 0 : case FD_KEYGUARD_ROLE_REPAIR: {
179 0 : int ping_ok = (!!( payload_mask & FD_KEYGUARD_PAYLOAD_PING )) &&
180 0 : fd_keyguard_authorize_ping( authority, data, sz, sign_type );
181 0 : int repair_ok = (!!( payload_mask & FD_KEYGUARD_PAYLOAD_REPAIR )) &&
182 0 : fd_keyguard_authorize_repair( authority, data, sz, sign_type );
183 0 : if( FD_UNLIKELY( !ping_ok && !repair_ok ) ) {
184 0 : FD_LOG_WARNING(( "unauthorized payload type for repair (mask=%#lx)", payload_mask ));
185 0 : return 0;
186 0 : }
187 0 : return 1;
188 0 : }
189 :
190 0 : case FD_KEYGUARD_ROLE_LEADER:
191 0 : if( FD_UNLIKELY( payload_mask != FD_KEYGUARD_PAYLOAD_SHRED ) ) {
192 0 : FD_LOG_WARNING(( "unauthorized payload type for leader (mask=%#lx)", payload_mask ));
193 0 : return 0;
194 0 : }
195 : /* no further restrictions on shred */
196 0 : return 1;
197 :
198 0 : case FD_KEYGUARD_ROLE_BUNDLE:
199 0 : if( FD_UNLIKELY( payload_mask != FD_KEYGUARD_PAYLOAD_BUNDLE ) ) {
200 0 : FD_LOG_WARNING(( "unauthorized payload type for bundle (mask=%#lx)", payload_mask ));
201 0 : return 0;
202 0 : }
203 : /* no further restrictions on bundle */
204 0 : return 1;
205 :
206 0 : case FD_KEYGUARD_ROLE_EVENT:
207 0 : if( FD_UNLIKELY( payload_mask != FD_KEYGUARD_PAYLOAD_EVENT ) ) {
208 0 : FD_LOG_WARNING(( "unauthorized payload type for event (mask=%#lx)", payload_mask ));
209 0 : return 0;
210 0 : }
211 : /* no further restrictions on event */
212 0 : return 1;
213 :
214 0 : case FD_KEYGUARD_ROLE_BUNDLE_CRANK:
215 0 : if( FD_UNLIKELY( payload_mask != FD_KEYGUARD_PAYLOAD_TXN ) ) {
216 0 : FD_LOG_WARNING(( "unauthorized payload type for event (mask=%#lx)", payload_mask ));
217 0 : return 0;
218 0 : }
219 0 : return fd_keyguard_authorize_bundle_crank_txn( authority, data, sz, sign_type );
220 :
221 0 : default:
222 0 : FD_LOG_WARNING(( "unsupported role=%#x", (uint)role ));
223 0 : return 0;
224 0 : }
225 0 : }
|