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