@cryptotaxi247 / kubo / commits / 4674f770b

Choosable key types at initialization

* add support for choosing a peer key type (e.g. RSA or Ed25519) when initializing the repo * test all variants of ipfs init: RSA, Ed25519 and default * update subdomain gateway sharness test to publish IPNS using RSA and Ed25519 keys * use default identity bit lengths defined in config repo instead of having separate defaults in go-ipfs * update config repo dependency Co-authored-by: Will Scott <will@cypherpunk.email> Co-authored-by: Petar Maymounkov <petarm@gmail.com>

Petar Maymounkov committed Jul 9, 2020 at 15:18 UTC 4674f770b7dde05f688d0f7c7fe972f6828b35e9
7 files changed +210 -100
cmd/ipfs/daemon.go
+9 -1
@@ -31,6 +31,7 @@ import (
31
32 cmds "github.com/ipfs/go-ipfs-cmds"
33 mprome "github.com/ipfs/go-metrics-prometheus"
34 + options "github.com/ipfs/interface-go-ipfs-core/options"
35 goprocess "github.com/jbenet/goprocess"
36 ma "github.com/multiformats/go-multiaddr"
37 manet "github.com/multiformats/go-multiaddr-net"
@@ -247,7 +248,14 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
248 }
249 }
250
250 - if err = doInit(os.Stdout, cctx.ConfigRoot, false, nBitsForKeypairDefault, profiles, conf); err != nil {
251 + identity, err := config.CreateIdentity(os.Stdout, []options.KeyGenerateOption{
252 + options.Key.Type(algorithmDefault),
253 + })
254 + if err != nil {
255 + return err
256 + }
257 +
258 + if err = doInit(os.Stdout, cctx.ConfigRoot, false, &identity, profiles, conf); err != nil {
259 return err
260 }
261 }
cmd/ipfs/init.go
+33 -9
@@ -19,13 +19,15 @@ import (
19 cmds "github.com/ipfs/go-ipfs-cmds"
20 config "github.com/ipfs/go-ipfs-config"
21 files "github.com/ipfs/go-ipfs-files"
22 + options "github.com/ipfs/interface-go-ipfs-core/options"
23 )
24
25 const (
25 - nBitsForKeypairDefault = 2048
26 - bitsOptionName = "bits"
27 - emptyRepoOptionName = "empty-repo"
28 - profileOptionName = "profile"
26 + algorithmDefault = options.RSAKey
27 + algorithmOptionName = "algorithm"
28 + bitsOptionName = "bits"
29 + emptyRepoOptionName = "empty-repo"
30 + profileOptionName = "profile"
31 )
32
33 var errRepoExists = errors.New(`ipfs configuration file already exists!
@@ -54,7 +56,8 @@ environment variable:
56 cmds.FileArg("default-config", false, false, "Initialize with the given configuration.").EnableStdin(),
57 },
58 Options: []cmds.Option{
57 - cmds.IntOption(bitsOptionName, "b", "Number of bits to use in the generated RSA private key.").WithDefault(nBitsForKeypairDefault),
59 + cmds.StringOption(algorithmOptionName, "a", "Cryptographic algorithm to use for key generation.").WithDefault(algorithmDefault),
60 + cmds.IntOption(bitsOptionName, "b", "Number of bits to use in the generated RSA private key."),
61 cmds.BoolOption(emptyRepoOptionName, "e", "Don't add and pin help files to the local storage."),
62 cmds.StringOption(profileOptionName, "p", "Apply profile settings to config. Multiple profiles can be separated by ','"),
63
@@ -82,7 +85,8 @@ environment variable:
85 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
86 cctx := env.(*oldcmds.Context)
87 empty, _ := req.Options[emptyRepoOptionName].(bool)
85 - nBitsForKeypair, _ := req.Options[bitsOptionName].(int)
88 + algorithm, _ := req.Options[algorithmOptionName].(string)
89 + nBitsForKeypair, nBitsGiven := req.Options[bitsOptionName].(int)
90
91 var conf *config.Config
92
@@ -106,8 +110,24 @@ environment variable:
110 }
111 }
112
113 + var err error
114 + var identity config.Identity
115 + if nBitsGiven {
116 + identity, err = config.CreateIdentity(os.Stdout, []options.KeyGenerateOption{
117 + options.Key.Size(nBitsForKeypair),
118 + options.Key.Type(algorithm),
119 + })
120 + } else {
121 + identity, err = config.CreateIdentity(os.Stdout, []options.KeyGenerateOption{
122 + options.Key.Type(algorithm),
123 + })
124 + }
125 + if err != nil {
126 + return err
127 + }
128 +
129 profiles, _ := req.Options[profileOptionName].(string)
110 - return doInit(os.Stdout, cctx.ConfigRoot, empty, nBitsForKeypair, profiles, conf)
130 + return doInit(os.Stdout, cctx.ConfigRoot, empty, &identity, profiles, conf)
131 },
132 }
133
@@ -129,7 +149,7 @@ func applyProfiles(conf *config.Config, profiles string) error {
149 return nil
150 }
151
132 -func doInit(out io.Writer, repoRoot string, empty bool, nBitsForKeypair int, confProfiles string, conf *config.Config) error {
152 +func doInit(out io.Writer, repoRoot string, empty bool, identity *config.Identity, confProfiles string, conf *config.Config) error {
153 if _, err := fmt.Fprintf(out, "initializing IPFS node at %s\n", repoRoot); err != nil {
154 return err
155 }
@@ -142,9 +162,13 @@ func doInit(out io.Writer, repoRoot string, empty bool, nBitsForKeypair int, con
162 return errRepoExists
163 }
164
165 + if identity == nil {
166 + return fmt.Errorf("No Identity provided for initialization")
167 + }
168 +
169 if conf == nil {
170 var err error
147 - conf, err = config.Init(out, nBitsForKeypair)
171 + conf, err = config.InitWithIdentity(*identity)
172 if err != nil {
173 return err
174 }
go.mod
+1 -1
@@ -32,7 +32,7 @@ require (
32 github.com/ipfs/go-ipfs-blockstore v0.1.4
33 github.com/ipfs/go-ipfs-chunker v0.0.5
34 github.com/ipfs/go-ipfs-cmds v0.2.9
35 - github.com/ipfs/go-ipfs-config v0.8.0
35 + github.com/ipfs/go-ipfs-config v0.9.0
36 github.com/ipfs/go-ipfs-ds-help v0.1.1
37 github.com/ipfs/go-ipfs-exchange-interface v0.0.1
38 github.com/ipfs/go-ipfs-exchange-offline v0.0.1
go.sum
+4
@@ -346,6 +346,10 @@ github.com/ipfs/go-ipfs-cmds v0.2.9 h1:zQTENe9UJrtCb2bOtRoDGjtuo3rQjmuPdPnVlqoBV
346 github.com/ipfs/go-ipfs-cmds v0.2.9/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk=
347 github.com/ipfs/go-ipfs-config v0.8.0 h1:4Tc7DC3dz4e7VadOjxXxFQGTQ1g7EYZClJ/ih8qOrxE=
348 github.com/ipfs/go-ipfs-config v0.8.0/go.mod h1:GQUxqb0NfkZmEU92PxqqqLVVFTLpoGGUlBaTyDaAqrE=
349 +github.com/ipfs/go-ipfs-config v0.8.1-0.20200714165010-0b2590596cd4 h1:gD1K9GUACg3QRyjJD5rxTW/dUEYJt2/a98nnCoISSOk=
350 +github.com/ipfs/go-ipfs-config v0.8.1-0.20200714165010-0b2590596cd4/go.mod h1:GQUxqb0NfkZmEU92PxqqqLVVFTLpoGGUlBaTyDaAqrE=
351 +github.com/ipfs/go-ipfs-config v0.9.0 h1:qTXJ9CyOyQv1LFJUMysxz8fi6RxxnP9QqcmiobuANvw=
352 +github.com/ipfs/go-ipfs-config v0.9.0/go.mod h1:GQUxqb0NfkZmEU92PxqqqLVVFTLpoGGUlBaTyDaAqrE=
353 github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
354 github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ=
355 github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
test/sharness/lib/test-lib.sh
+1 -1
@@ -445,7 +445,7 @@ file_size() {
445
446 test_check_peerid() {
447 peeridlen=$(echo "$1" | tr -dC "[:alnum:]" | wc -c | tr -d " ") &&
448 - test "$peeridlen" = "46" || {
448 + test "$peeridlen" = "46" -o "$peeridlen" = "52" -o "$peeridlen" = "62" || {
449 echo "Bad peerid '$1' with len '$peeridlen'"
450 return 1
451 }
test/sharness/t0020-init.sh
+144 -83
@@ -50,93 +50,154 @@ test_expect_success "ipfs cat no repo message looks good" '
50 test_path_cmp cat_fail_exp cat_fail_out
51 '
52
53 -# test that init succeeds
54 -test_expect_success "ipfs init succeeds" '
55 - export IPFS_PATH="$(pwd)/.ipfs" &&
56 - echo "IPFS_PATH: \"$IPFS_PATH\"" &&
57 - BITS="2048" &&
58 - ipfs init --bits="$BITS" >actual_init ||
59 - test_fsh cat actual_init
60 -'
61 -
62 -test_expect_success ".ipfs/ has been created" '
63 - test -d ".ipfs" &&
64 - test -f ".ipfs/config" &&
65 - test -d ".ipfs/datastore" &&
66 - test -d ".ipfs/blocks" &&
67 - test ! -f ._check_writeable ||
68 - test_fsh ls -al .ipfs
69 -'
70 -
71 -test_expect_success "ipfs config succeeds" '
72 - echo /ipfs >expected_config &&
73 - ipfs config Mounts.IPFS >actual_config &&
74 - test_cmp expected_config actual_config
75 -'
76 -
77 -test_expect_success "ipfs peer id looks good" '
78 - PEERID=$(ipfs config Identity.PeerID) &&
79 - test_check_peerid "$PEERID"
80 -'
81 -
82 -test_expect_success "ipfs init output looks good" '
83 - STARTFILE="ipfs cat /ipfs/$HASH_WELCOME_DOCS/readme" &&
84 - echo "initializing IPFS node at $IPFS_PATH" >expected &&
85 - echo "generating $BITS-bit RSA keypair...done" >>expected &&
86 - echo "peer identity: $PEERID" >>expected &&
87 - echo "to get started, enter:" >>expected &&
88 - printf "\\n\\t$STARTFILE\\n\\n" >>expected &&
89 - test_cmp expected actual_init
90 -'
91 -
92 -test_expect_success "Welcome readme exists" '
93 - ipfs cat /ipfs/$HASH_WELCOME_DOCS/readme
94 -'
95 -
96 -test_expect_success "clean up ipfs dir" '
97 - rm -rf "$IPFS_PATH"
98 -'
99 -
100 -test_expect_success "'ipfs init --empty-repo' succeeds" '
101 - BITS="2048" &&
102 - ipfs init --bits="$BITS" --empty-repo >actual_init
103 -'
104 -
105 -test_expect_success "ipfs peer id looks good" '
106 - PEERID=$(ipfs config Identity.PeerID) &&
107 - test_check_peerid "$PEERID"
108 -'
109 -
110 -test_expect_success "'ipfs init --empty-repo' output looks good" '
111 - echo "initializing IPFS node at $IPFS_PATH" >expected &&
112 - echo "generating $BITS-bit RSA keypair...done" >>expected &&
113 - echo "peer identity: $PEERID" >>expected &&
114 - test_cmp expected actual_init
115 -'
116 -
117 -test_expect_success "Welcome readme doesn't exist" '
118 - test_must_fail ipfs cat /ipfs/$HASH_WELCOME_DOCS/readme
119 -'
120 -
121 -test_expect_success "ipfs id agent string contains correct version" '
122 - ipfs id -f "<aver>" | grep $(ipfs version -n)
123 -'
124 -
125 -test_expect_success "clean up ipfs dir" '
126 - rm -rf "$IPFS_PATH"
127 -'
53 +# $1 must be one of 'rsa', 'ed25519' or '' (for default key algorithm).
54 +test_ipfs_init_flags() {
55 + TEST_ALG=$1
56 +
57 + # test that init succeeds
58 + test_expect_success "ipfs init succeeds" '
59 + export IPFS_PATH="$(pwd)/.ipfs" &&
60 + echo "IPFS_PATH: \"$IPFS_PATH\"" &&
61 + RSA_BITS="2048" &&
62 + case $TEST_ALG in
63 + "rsa")
64 + ipfs init --algorithm=rsa --bits="$RSA_BITS" >actual_init || test_fsh cat actual_init
65 + ;;
66 + "ed25519")
67 + ipfs init --algorithm=ed25519 >actual_init || test_fsh cat actual_init
68 + ;;
69 + *)
70 + ipfs init --algorithm=rsa --bits="$RSA_BITS" >actual_init || test_fsh cat actual_init
71 + ;;
72 + esac
73 + '
74 +
75 + test_expect_success ".ipfs/ has been created" '
76 + test -d ".ipfs" &&
77 + test -f ".ipfs/config" &&
78 + test -d ".ipfs/datastore" &&
79 + test -d ".ipfs/blocks" &&
80 + test ! -f ._check_writeable ||
81 + test_fsh ls -al .ipfs
82 + '
83 +
84 + test_expect_success "ipfs config succeeds" '
85 + echo /ipfs >expected_config &&
86 + ipfs config Mounts.IPFS >actual_config &&
87 + test_cmp expected_config actual_config
88 + '
89 +
90 + test_expect_success "ipfs peer id looks good" '
91 + PEERID=$(ipfs config Identity.PeerID) &&
92 + test_check_peerid "$PEERID"
93 + '
94 +
95 + test_expect_success "ipfs init output looks good" '
96 + STARTFILE="ipfs cat /ipfs/$HASH_WELCOME_DOCS/readme" &&
97 +
98 + echo "generating $RSA_BITS-bit RSA keypair...done" >rsa_expected &&
99 + echo "peer identity: $PEERID" >>rsa_expected &&
100 + echo "initializing IPFS node at $IPFS_PATH" >>rsa_expected &&
101 + echo "to get started, enter:" >>rsa_expected &&
102 + printf "\\n\\t$STARTFILE\\n\\n" >>rsa_expected &&
103 +
104 + echo "generating ED25519 keypair...done" >ed25519_expected &&
105 + echo "peer identity: $PEERID" >>ed25519_expected &&
106 + echo "initializing IPFS node at $IPFS_PATH" >>ed25519_expected &&
107 + echo "to get started, enter:" >>ed25519_expected &&
108 + printf "\\n\\t$STARTFILE\\n\\n" >>ed25519_expected &&
109 +
110 + case $TEST_ALG in
111 + rsa)
112 + test_cmp rsa_expected actual_init
113 + ;;
114 + ed25519)
115 + test_cmp ed25519_expected actual_init
116 + ;;
117 + *)
118 + test_cmp rsa_expected actual_init
119 + ;;
120 + esac
121 + '
122 +
123 + test_expect_success "Welcome readme exists" '
124 + ipfs cat /ipfs/$HASH_WELCOME_DOCS/readme
125 + '
126 +
127 + test_expect_success "clean up ipfs dir" '
128 + rm -rf "$IPFS_PATH"
129 + '
130 +
131 + test_expect_success "'ipfs init --empty-repo' succeeds" '
132 + RSA_BITS="2048" &&
133 + case $TEST_ALG in
134 + rsa)
135 + ipfs init --algorithm=rsa --bits="$RSA_BITS" --empty-repo >actual_init
136 + ;;
137 + ed25519)
138 + ipfs init --algorithm=ed25519 --empty-repo >actual_init
139 + ;;
140 + *)
141 + ipfs init --bits="$RSA_BITS" --empty-repo >actual_init
142 + ;;
143 + esac
144 + '
145 +
146 + test_expect_success "ipfs peer id looks good" '
147 + PEERID=$(ipfs config Identity.PeerID) &&
148 + test_check_peerid "$PEERID"
149 + '
150 +
151 + test_expect_success "'ipfs init --empty-repo' output looks good" '
152 +
153 + echo "generating $RSA_BITS-bit RSA keypair...done" >rsa_expected &&
154 + echo "peer identity: $PEERID" >>rsa_expected &&
155 + echo "initializing IPFS node at $IPFS_PATH" >>rsa_expected &&
156 +
157 + echo "generating ED25519 keypair...done" >ed25519_expected &&
158 + echo "peer identity: $PEERID" >>ed25519_expected &&
159 + echo "initializing IPFS node at $IPFS_PATH" >>ed25519_expected &&
160 +
161 + case $TEST_ALG in
162 + rsa)
163 + test_cmp rsa_expected actual_init
164 + ;;
165 + ed25519)
166 + test_cmp ed25519_expected actual_init
167 + ;;
168 + *)
169 + test_cmp rsa_expected actual_init
170 + ;;
171 + esac
172 + '
173 +
174 + test_expect_success "Welcome readme doesn't exist" '
175 + test_must_fail ipfs cat /ipfs/$HASH_WELCOME_DOCS/readme
176 + '
177 +
178 + test_expect_success "ipfs id agent string contains correct version" '
179 + ipfs id -f "<aver>" | grep $(ipfs version -n)
180 + '
181 +
182 + test_expect_success "clean up ipfs dir" '
183 + rm -rf "$IPFS_PATH"
184 + '
185 +}
186 +test_ipfs_init_flags 'ed25519'
187 +test_ipfs_init_flags 'rsa'
188 +test_ipfs_init_flags ''
189
190 # test init profiles
191 test_expect_success "'ipfs init --profile' with invalid profile fails" '
131 - BITS="2048" &&
132 - test_must_fail ipfs init --bits="$BITS" --profile=nonexistent_profile 2> invalid_profile_out
192 + RSA_BITS="2048" &&
193 + test_must_fail ipfs init --bits="$RSA_BITS" --profile=nonexistent_profile 2> invalid_profile_out
194 EXPECT="Error: invalid configuration profile: nonexistent_profile" &&
195 grep "$EXPECT" invalid_profile_out
196 '
197
198 test_expect_success "'ipfs init --profile' succeeds" '
138 - BITS="2048" &&
139 - ipfs init --bits="$BITS" --profile=server
199 + RSA_BITS="2048" &&
200 + ipfs init --bits="$RSA_BITS" --profile=server
201 '
202
203 test_expect_success "'ipfs config Swarm.AddrFilters' looks good" '
@@ -149,8 +210,8 @@ test_expect_success "clean up ipfs dir" '
210 '
211
212 test_expect_success "'ipfs init --profile=test' succeeds" '
152 - BITS="2048" &&
153 - ipfs init --bits="$BITS" --profile=test
213 + RSA_BITS="2048" &&
214 + ipfs init --bits="$RSA_BITS" --profile=test
215 '
216
217 test_expect_success "'ipfs config Bootstrap' looks good" '
@@ -182,8 +243,8 @@ test_expect_success "clean up ipfs dir" '
243 '
244
245 test_expect_success "'ipfs init --profile=lowpower' succeeds" '
185 - BITS="2048" &&
186 - ipfs init --bits="$BITS" --profile=lowpower
246 + RSA_BITS="2048" &&
247 + ipfs init --bits="$RSA_BITS" --profile=lowpower
248 '
249
250 test_expect_success "'ipfs config Discovery.Routing' looks good" '
test/sharness/t0114-gateway-subdomains.sh
+18 -5
@@ -94,6 +94,7 @@ test_expect_success "Add test text file" '
94 CIDv1=$(echo $CID_VAL | ipfs add --cid-version 1 -Q)
95 CIDv0=$(echo $CID_VAL | ipfs add --cid-version 0 -Q)
96 CIDv0to1=$(echo "$CIDv0" | ipfs cid base32)
97 + echo CIDv0to1=${CIDv0to1}
98 '
99
100 test_expect_success "Add the test directory" '
@@ -107,13 +108,25 @@ test_expect_success "Add the test directory" '
108 DIR_CID=$(ipfs add -Qr --cid-version 1 testdirlisting)
109 '
110
110 -test_expect_success "Publish test text file to IPNS" '
111 - PEERID=$(ipfs id --format="<id>")
111 +test_expect_success "Publish test text file to IPNS using RSA keys" '
112 + PEERID=$(ipfs key gen -f=b58mh --type=rsa --size=2048 test_key_rsa | head -n1 | tr -d "\n")
113 IPNS_IDv0=$(echo "$PEERID" | ipfs cid format -v 0)
114 IPNS_IDv1=$(echo "$PEERID" | ipfs cid format -v 1 --codec libp2p-key -b base36)
115 IPNS_IDv1_DAGPB=$(echo "$IPNS_IDv0" | ipfs cid format -v 1 -b base36)
116 test_check_peerid "${PEERID}" &&
116 - ipfs name publish --allow-offline -Q "/ipfs/$CIDv1" > name_publish_out &&
117 + ipfs name publish --key test_key_rsa --allow-offline -Q "/ipfs/$CIDv1" > name_publish_out &&
118 + ipfs name resolve "$PEERID" > output &&
119 + printf "/ipfs/%s\n" "$CIDv1" > expected2 &&
120 + test_cmp expected2 output
121 +'
122 +
123 +test_expect_success "Publish test text file to IPNS using ED25519 keys" '
124 + PEERID=$(ipfs key gen -f=b36cid --type=ed25519 test_key_ed25519 | head -n1 | tr -d "\n") &&
125 + IPNS_IDv0=$PEERID
126 + IPNS_IDv1=$PEERID
127 + IPNS_IDv1_DAGPB=$(echo "$IPNS_IDv0" | ipfs cid format -v 1 -b base32)
128 + test_check_peerid "${PEERID}" &&
129 + ipfs name publish --key test_key_ed25519 --allow-offline -Q "/ipfs/$CIDv1" > name_publish_out &&
130 ipfs name resolve "$PEERID" > output &&
131 printf "/ipfs/%s\n" "$CIDv1" > expected2 &&
132 test_cmp expected2 output
@@ -272,7 +285,7 @@ test_localhost_gateway_response_should_contain \
285 "$CID_VAL"
286
287 test_localhost_gateway_response_should_contain \
275 - "request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \
288 + "localhost request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \
289 "http://${IPNS_IDv1_DAGPB}.ipns.localhost:$GWAY_PORT" \
290 "Location: http://${IPNS_IDv1}.ipns.localhost:$GWAY_PORT/"
291
@@ -410,7 +423,7 @@ test_hostname_gateway_response_should_contain \
423 "$CID_VAL"
424
425 test_hostname_gateway_response_should_contain \
413 - "request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \
426 + "hostname request for {CIDv1-dag-pb}.ipns.localhost redirects to CID with libp2p-key multicodec" \
427 "${IPNS_IDv1_DAGPB}.ipns.example.com" \
428 "http://127.0.0.1:$GWAY_PORT" \
429 "Location: http://${IPNS_IDv1}.ipns.example.com/"