From 7f15be2ae570fea8f7a9b019b6863cd8adfb7798 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Mon, 3 Aug 2020 15:46:15 -0400 Subject: [PATCH] switch ipfs key import/export to use files instead of strings --- core/commands/keystore.go | 79 ++++++++++++++++++++----------- test/sharness/lib/test-lib.sh | 16 ------- test/sharness/t0165-keystore.sh | 83 ++++++++++++++++++++++++--------- 3 files changed, 114 insertions(+), 64 deletions(-) diff --git a/core/commands/keystore.go b/core/commands/keystore.go index a34fdcc80..abf0dc8a2 100644 --- a/core/commands/keystore.go +++ b/core/commands/keystore.go @@ -1,17 +1,20 @@ package commands import ( + "bytes" "fmt" "io" + "io/ioutil" + "os" "text/tabwriter" cmds "github.com/ipfs/go-ipfs-cmds" cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv" + "github.com/ipfs/go-ipfs/core/commands/e" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" options "github.com/ipfs/interface-go-ipfs-core/options" "github.com/libp2p/go-libp2p-core/crypto" peer "github.com/libp2p/go-libp2p-core/peer" - "github.com/mr-tron/base58/base58" mbase "github.com/multiformats/go-multibase" ) @@ -47,10 +50,6 @@ type KeyOutput struct { Id string } -type ExportKeyOutput struct { - Sk string -} - type KeyOutputList struct { Keys []KeyOutput } @@ -152,22 +151,22 @@ func formatID(id peer.ID, formatLabel string) string { } } -func encodeSKForExport(sk crypto.PrivKey) (string, error) { - data, err := crypto.MarshalPrivateKey(sk) - if err != nil { - return "", err - } - return base58.Encode(data), nil -} - var keyExportCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Export a keypair", + ShortDescription: ` +Exports a named libp2p key to disk. + +By default, the output will be stored at './', but an alternate +path can be specified with '--output=' or '-o='. +`, }, Arguments: []cmds.Argument{ cmds.StringArg("name", true, false, "name of key to export").EnableStdin(), }, - Options: []cmds.Option{}, + Options: []cmds.Option{ + cmds.StringOption(outputOptionName, "o", "The path where the output should be stored."), + }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { name := req.Arguments[0] @@ -191,22 +190,44 @@ var keyExportCmd = &cmds.Command{ return fmt.Errorf("key with name '%s' doesn't exist", name) } - encoded, err := encodeSKForExport(sk) + encoded, err := crypto.MarshalPrivateKey(sk) if err != nil { return err } - return cmds.EmitOnce(res, &ExportKeyOutput{ - Sk: encoded, - }) + return res.Emit(bytes.NewReader(encoded)) }, - Encoders: cmds.EncoderMap{ - cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, ko *ExportKeyOutput) error { - _, err := w.Write([]byte(ko.Sk + "\n")) - return err - }), + PostRun: cmds.PostRunMap{ + cmds.CLI: func(res cmds.Response, re cmds.ResponseEmitter) error { + req := res.Request() + + v, err := res.Next() + if err != nil { + return err + } + + outReader, ok := v.(io.Reader) + if !ok { + return e.New(e.TypeErr(outReader, v)) + } + + outPath := getOutPath(req) + + // create file + file, err := os.Create(outPath) + if err != nil { + return err + } + defer file.Close() + + _, err = io.Copy(file, outReader) + if err != nil { + return err + } + + return nil + }, }, - Type: ExportKeyOutput{}, } var keyImportCmd = &cmds.Command{ @@ -218,7 +239,7 @@ var keyImportCmd = &cmds.Command{ }, Arguments: []cmds.Argument{ cmds.StringArg("name", true, false, "name to associate with key in keychain"), - cmds.StringArg("key", true, false, "key provided by generate or export"), + cmds.FileArg("key", true, false, "key provided by generate or export"), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { name := req.Arguments[0] @@ -227,9 +248,13 @@ var keyImportCmd = &cmds.Command{ return fmt.Errorf("cannot import key with name 'self'") } - encoded := req.Arguments[1] + file, err := cmdenv.GetFileArg(req.Files.Entries()) + if err != nil { + return err + } + defer file.Close() - data, err := base58.Decode(encoded) + data, err := ioutil.ReadAll(file) if err != nil { return err } diff --git a/test/sharness/lib/test-lib.sh b/test/sharness/lib/test-lib.sh index bada4b525..c71697175 100644 --- a/test/sharness/lib/test-lib.sh +++ b/test/sharness/lib/test-lib.sh @@ -483,22 +483,6 @@ test_check_ed25519_b36cid_peerid() { } } -test_check_rsa2048_sk() { - sklen=$(echo "$1" | tr -dC "[:alnum:]" | wc -c | tr -d " ") && - if (($sklen < 1600)); then - echo "Bad RSA2048 sk '$1' with len '$sklen'" - return 1 - fi -} - -test_check_ed25519_sk() { - sklen=$(echo "$1" | tr -dC "[:alnum:]" | wc -c | tr -d " ") && - test "$sklen" = "93" || { - echo "Bad ED25519 sk '$1' with len '$sklen'" - return 1 - } -} - convert_tcp_maddr() { echo $1 | awk -F'/' '{ printf "%s:%s", $3, $5 }' } diff --git a/test/sharness/t0165-keystore.sh b/test/sharness/t0165-keystore.sh index 2f57bc99c..035c7e1e2 100755 --- a/test/sharness/t0165-keystore.sh +++ b/test/sharness/t0165-keystore.sh @@ -18,8 +18,9 @@ test_check_rsa2048_b58mh_peerid $PEERID ' test_expect_success "test RSA key sk export format" ' -SK=$(ipfs key export key_rsa) && -test_check_rsa2048_sk $SK +ipfs key export key_rsa && +test_check_rsa2048_sk key_rsa && +rm key_rsa ' test_expect_success "test RSA key B36CID multihash format" ' @@ -34,8 +35,9 @@ test_check_ed25519_b36cid_peerid $PEERID ' test_expect_success "test ED25519 key sk export format" ' -SK=$(ipfs key export key_ed25519) && -test_check_ed25519_sk $SK +ipfs key export key_ed25519 && +test_check_ed25519_sk key_ed25519 && +rm key_ed25519 ' test_expect_success "test ED25519 key B36CID multihash format" ' @@ -47,36 +49,59 @@ ipfs key rm key_ed25519 test_expect_success "create a new rsa key" ' - rsahash=$(ipfs key gen -f=b58mh foobarsa --type=rsa --size=2048) + rsahash=$(ipfs key gen -f=b58mh generated_rsa_key --type=rsa --size=2048) + echo $rsahash > rsa_key_id ' test_expect_success "create a new ed25519 key" ' - edhash=$(ipfs key gen -f=b58mh bazed --type=ed25519) - ' - - test_expect_success "import an rsa key" ' - echo "B9bLmHeKLQU1hX23meSn2kJiNW7AZ31C6PBNSYumejXB13vxSVvViZDkEnchAH4BTs9yVnBNZKZYLwykaCohzxTntesTCVaBhZR2Br2Swav2NXwVBhfrUbaBTrR2248KfbVxSiUdkpFn8kcAmUGwp2KGMGRmq85WreGFDdAvzz8ruN2EFfWSHLc1YeUxHeUgKsQm3N13uF7q5x4qvjWM6yvMWNY7JtZrihT8BZQhgb2ezR4iYPjXZTtPZWsLbrrhUvHhxSn1NsTw6NZ7Jbs84qMXXnH56BmT8J9LugRhQQvgBquSoS1m7aeD2y1L1A7mueVDYGLDzgxRSt5CohY7VVMdheUpPiq44CicuYt5YgbbuE3wMHntn6sd9QSYw7f4SjjKdw7Jhy5fNW29SkHvpLfZKfqzBNhSfHsofXVEASDpfr5mqws1eQTztqvvZhHXQxAoxxP3PK6TfDnATdLdV3Cy5v6nLt7ppsBj54hif5EZneHMLeYP8bYLbELQ2fZdoprpnKVBsMY1nWvgrMKUTpLjoKB6bzAZYuXaYVtmrdhESmKCyE12yEyvCcD8DJQU6JjqaD1DyVSPNkL3ze26Mm3ZyiFEH7M4XirUsPLrsj41Qt1xGaVGNEdkdthihytTZxxnmgyAptZMUNfSviBfH1tVbfoXFtBGU8eYMLdSHFqxSktT1mqeiWatxMQZ8pTeA9VCvAp9RTSRFkTQR9uP6w6qTzRD9cFcH4HyCEc5TJpiZdP7u9RjaEo2S3P9VkHfmqCH4McpLgw7He9nm7rf9JA2Gh7ubTKy5e6dJUWojgYhGS4KGe3yKGFhLaNgRiME63fUEFSnN2ZvCSM9qsrj34q2h8962xBod9hCVEDfk4tfmHu1UHX5AGaW6mk3pzqKKVYTTWXi84JSH7vzKPmQuhwaAR9Ye3Jbdzehp4xhrT5aFCjnz3r5qNv2zz48Fq5bGc1RUh88PUMT3z6kuzv6B1eXTLYpeu9gGdjc5C9DQDTYPfcHWn7dSHr4AGV1sN6SwVy8W5LZdMAZaeXCDn9iXDwbeD2DYd2ozVCEzceygVzpVdnueNx5FmG6zHtGzfuStr4Jj85sbd2jUGh4ES2bMU41jw2gJ6ujjf6CrxZpCWhXz6NJpAS9njcDFXuspf7otbMjCB6TzwokJwEse31nGUZQdhQgXn23vnZtxwCV621uXFbm7xVACRZKeuXgw8VdEVaXGvf2V4DdhjZnjmePBbTeJ7WjABavLcpMqZJH7FgaLxazFqk9RXtnfUEbVAAhuZzxz6L8Z6axHwz3a4EZtALRjfFjn6xjaUtsWXYW8P6F7femM6UHx3qXMo43hKC7oxnd6Tfta972dgyQfSoBwWkWzB8cvaJreNh4bdLNkw6mty86NXGKyijv83LR1HjbnUoTwPbEMX8JyzLfMf3qiWzwf6MHrXprwygmEpNc6w8tNNivmcWyCX3wmPkMKK1bmi5TCHoUtRrxcyXKhmuyo6zzag8KyK6iZaRbMiFiUJBi5VYwidMutkexWo8SRqfSV5yp2kxswknmpeVTnXBhVEy3anMEiD6bV48AnbF6SfKAi2DGBFqxBFfpFEbYtPauHiYYzZX1epqvKxY23xA9J8FosMk4yYN4Ps7Rh" >> importkey - imphash=$(ipfs key import -f=b58mh quxel $(cat importkey)) + edhash=$(ipfs key gen -f=b58mh generated_ed25519_key --type=ed25519) + echo $edhash > ed25519_key_id ' - test_expect_success "exported key matches imported" ' - ipfs key export quxel >> exportkey && - test_cmp importkey exportkey + test_expect_success "export and import rsa key" ' + ipfs key export generated_rsa_key && + ipfs key rm generated_rsa_key && + ipfs key import generated_rsa_key generated_rsa_key > roundtrip_rsa_key_id && + test_cmp rsa_key_id roundtrip_rsa_key_id + ' + + test_expect_success "export and import ed25519 key" ' + ipfs key export generated_ed25519_key && + ipfs key rm generated_ed25519_key && + ipfs key import generated_ed25519_key generated_ed25519_key > roundtrip_ed25519_key_id && + test_cmp ed25519_key_id roundtrip_ed25519_key_id + ' + + test_expect_success "test export file option" ' + ipfs key export generated_rsa_key -o=named_rsa_export_file && + test_cmp generated_rsa_key named_rsa_export_file && + ipfs key export generated_ed25519_key -o=named_ed25519_export_file && + test_cmp generated_ed25519_key named_ed25519_export_file ' test_expect_success "key export can't export self" ' test_must_fail ipfs key export self 2>&1 | tee key_exp_out && + grep -q "Error: cannot export key with name" key_exp_out && + test_must_fail ipfs key export self -o=selfexport 2>&1 | tee key_exp_out && grep -q "Error: cannot export key with name" key_exp_out ' test_expect_success "key import can't import self" ' - test_must_fail ipfs key import self $(cat importkey) 2>&1 | tee key_imp_out && - grep -q "Error: cannot import key with name" key_imp_out + ipfs key gen overwrite_self_import && + ipfs key export overwrite_self_import && + test_must_fail ipfs key import self overwrite_self_import 2>&1 | tee key_imp_out && + grep -q "Error: cannot import key with name" key_imp_out && + ipfs key rm overwrite_self_import && + rm overwrite_self_import + ' + + test_expect_success "add a default key" ' + ipfs key gen quxel ' test_expect_success "all keys show up in list output" ' - echo bazed > list_exp && - echo foobarsa >> list_exp && + echo generated_ed25519_key > list_exp && + echo generated_rsa_key >> list_exp && echo quxel >> list_exp && echo self >> list_exp ipfs key list -f=b58mh > list_out && @@ -94,8 +119,8 @@ ipfs key rm key_ed25519 ' test_expect_success "key rm remove a key" ' - ipfs key rm foobarsa - echo bazed > list_exp && + ipfs key rm generated_rsa_key + echo generated_ed25519_key > list_exp && echo quxel >> list_exp && echo self >> list_exp ipfs key list -f=b58mh > list_out && @@ -108,7 +133,7 @@ ipfs key rm key_ed25519 ' test_expect_success "key rename rename a key" ' - ipfs key rename bazed fooed + ipfs key rename generated_ed25519_key fooed echo fooed > list_exp && echo quxel >> list_exp && echo self >> list_exp @@ -134,6 +159,22 @@ ipfs key rm key_ed25519 ' } +test_check_rsa2048_sk() { + sklen=$(ls -l $1 | awk '{print $5}') && + test "$sklen" -lt "1600" && test "$sklen" -gt "1000" || { + echo "Bad RSA2048 sk '$1' with len '$sklen'" + return 1 + } +} + +test_check_ed25519_sk() { + sklen=$(ls -l $1 | awk '{print $5}') && + test "$sklen" -lt "100" && test "$sklen" -gt "30" || { + echo "Bad ED25519 sk '$1' with len '$sklen'" + return 1 + } +} + test_key_cmd test_done