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