Line data Source code
1 : #include "../fd_config.h"
2 :
3 : #include "../fd_file_util.h"
4 : #include "../../../disco/keyguard/fd_keyload.h"
5 :
6 : #include <errno.h>
7 : #include <fcntl.h>
8 : #include <unistd.h>
9 : #include <sys/stat.h>
10 : #include <sys/random.h>
11 :
12 : typedef enum {
13 : CMD_NEW_IDENTITY,
14 : CMD_NEW_VOTE_ACCOUNT,
15 : CMD_PUBKEY,
16 : } cmd_type_t;
17 :
18 : void
19 : keys_cmd_args( int * pargc,
20 : char *** pargv,
21 0 : args_t * args) {
22 0 : if( FD_UNLIKELY( *pargc < 2 ) ) goto err;
23 :
24 0 : if( FD_LIKELY( !strcmp( *pargv[ 0 ], "new" ) ) ) {
25 0 : (*pargc)--;
26 0 : (*pargv)++;
27 0 : if( FD_LIKELY( !strcmp( *pargv[ 0 ], "identity" ) ) ) args->keys.cmd = CMD_NEW_IDENTITY;
28 0 : else if( FD_LIKELY( !strcmp( *pargv[ 0 ], "vote" ) ) ) args->keys.cmd = CMD_NEW_VOTE_ACCOUNT;
29 0 : }
30 0 : else if( FD_LIKELY( !strcmp( *pargv[ 0 ], "pubkey" ) ) ) {
31 0 : (*pargc)--;
32 0 : (*pargv)++;
33 0 : if( FD_UNLIKELY( *pargc < 1 ) ) goto err;
34 0 : args->keys.cmd = CMD_PUBKEY;
35 0 : fd_memcpy( args->keys.file_path, *pargv[ 0 ], sizeof( args->keys.file_path ) );
36 0 : }
37 0 : else goto err;
38 :
39 0 : (*pargc)--;
40 0 : (*pargv)++;
41 :
42 0 : return;
43 :
44 0 : err:
45 0 : FD_LOG_ERR(( "unrecognized subcommand `%s`\nusage:\n"
46 0 : " keys new identity\n"
47 0 : " keys new vote\n"
48 0 : " keys pubkey <path-to-keyfile>\n",
49 0 : *pargv[0] ));
50 0 : }
51 :
52 : void FD_FN_SENSITIVE
53 : generate_keypair( char const * keyfile,
54 : config_t const * config,
55 0 : int use_grnd_random ) {
56 0 : uint flags = use_grnd_random ? GRND_RANDOM : 0U;
57 :
58 0 : uchar keypair[ 64 ];
59 0 : long bytes_produced = 0L;
60 0 : while( FD_LIKELY( bytes_produced<32L ) ) {
61 0 : long n = getrandom( keypair+bytes_produced, (ulong)(32-bytes_produced), flags );
62 0 : if( FD_UNLIKELY( -1==n ) ) FD_LOG_ERR(( "could not create keypair, getrandom() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
63 0 : bytes_produced += n;
64 0 : }
65 :
66 0 : fd_sha512_t _sha[ 1 ];
67 0 : fd_sha512_t * sha = fd_sha512_join( fd_sha512_new( _sha ) );
68 0 : if( FD_UNLIKELY( !sha ) ) FD_LOG_ERR(( "could not create keypair, fd_sha512 join failed" ));
69 0 : fd_ed25519_public_from_private( keypair+32UL, keypair, sha );
70 :
71 : /* Switch to non-root uid/gid for file creation. Permissions checks
72 : are still done as root. */
73 0 : gid_t gid = getgid();
74 0 : uid_t uid = getuid();
75 0 : if( FD_LIKELY( !gid && setegid( config->gid ) ) ) FD_LOG_ERR(( "setegid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
76 0 : if( FD_LIKELY( !uid && seteuid( config->uid ) ) ) FD_LOG_ERR(( "seteuid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
77 :
78 : /* find last `/` in keyfile and zero it */
79 0 : char keyfile_copy[ PATH_MAX ] = {0};
80 0 : strncpy( keyfile_copy, keyfile, sizeof( keyfile_copy )-1UL );
81 0 : char * last_slash = strrchr( keyfile_copy, '/' );
82 0 : if( FD_LIKELY( last_slash ) ) {
83 0 : *last_slash = '\0';
84 0 : if( FD_UNLIKELY( -1==fd_file_util_mkdir_all( keyfile_copy, config->uid, config->gid ) ) ) {
85 0 : FD_LOG_ERR(( "could not create keypair, `mkdir -p %s` failed (%i-%s)", keyfile_copy, errno, fd_io_strerror( errno ) ));
86 0 : }
87 0 : }
88 :
89 0 : int fd = open( keyfile, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR );
90 0 : if( FD_UNLIKELY( -1==fd ) ) {
91 0 : if( FD_LIKELY( errno==EEXIST ) ) FD_LOG_ERR(( "could not create keypair as the keyfile `%s` already exists", keyfile ));
92 0 : else FD_LOG_ERR(( "could not create keypair, open(%s) failed (%i-%s)", keyfile, errno, fd_io_strerror( errno ) ));
93 0 : }
94 :
95 0 : if( FD_UNLIKELY( write( fd, "[", 1 )!=1L ) ) FD_LOG_ERR(( "could not create keypair, write() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
96 :
97 0 : for( ulong i=0UL; i<64UL; i++ ) {
98 0 : if( FD_LIKELY( i ) ) {
99 0 : if( FD_UNLIKELY( write( fd, ",", 1 )!=1L ) ) FD_LOG_ERR(( "could not create keypair, write() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
100 0 : }
101 :
102 0 : char digits[ 4 ];
103 0 : ulong digits_len;
104 0 : FD_TEST( fd_cstr_printf_check( digits, sizeof( digits ), &digits_len, "%d", keypair[ i ] ) );
105 0 : if( FD_UNLIKELY( write( fd, digits, digits_len )!=(long)digits_len ) ) FD_LOG_ERR(( "could not create keypair, write() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
106 0 : }
107 :
108 0 : if( FD_UNLIKELY( write( fd, "]", 1 )!=1L ) ) FD_LOG_ERR(( "could not create keypair, write() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
109 0 : if( FD_UNLIKELY( close( fd ) ) ) FD_LOG_ERR(( "could not create keypair, close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
110 :
111 0 : FD_LOG_NOTICE(( "successfully created keypair in `%s`", keyfile ));
112 :
113 0 : if( FD_UNLIKELY( seteuid( uid ) ) ) FD_LOG_ERR(( "seteuid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
114 0 : if( FD_UNLIKELY( setegid( gid ) ) ) FD_LOG_ERR(( "setegid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
115 :
116 0 : fd_memset_explicit( keypair, 0, 64UL );
117 0 : }
118 :
119 : void
120 0 : keys_pubkey( const char * file_path ) {
121 0 : uchar const * pubkey = fd_keyload_load( file_path, 1 );
122 0 : char pubkey_str[ FD_BASE58_ENCODED_32_SZ ];
123 0 : fd_base58_encode_32( pubkey, NULL, pubkey_str );
124 0 : FD_LOG_STDOUT(( "%s\n", pubkey_str ));
125 0 : }
126 :
127 : void
128 : keys_cmd_fn( args_t * args,
129 0 : config_t * config ) {
130 0 : if( FD_LIKELY( args->keys.cmd == CMD_NEW_IDENTITY ) ) {
131 0 : generate_keypair( config->consensus.identity_path, config, 1 );
132 0 : } else if( FD_LIKELY( args->keys.cmd == CMD_NEW_VOTE_ACCOUNT ) ) {
133 0 : if( FD_UNLIKELY( !strcmp( config->consensus.vote_account_path, "" ) ) )
134 0 : FD_LOG_ERR(( "Cannot create a vote account keypair because your validator is not configured "
135 0 : "to vote. Please set [consensus.vote_account_path] in your configuration file." ));
136 :
137 0 : generate_keypair( config->consensus.vote_account_path, config, 1 );
138 0 : } else if( FD_LIKELY( args->keys.cmd == CMD_PUBKEY ) ) {
139 0 : keys_pubkey( args->keys.file_path );
140 0 : } else {
141 0 : FD_LOG_ERR(( "unknown key type `%lu`", args->keys.cmd ));
142 0 : }
143 0 : }
|