diff --git a/command/certificate/fingerprint.go b/command/certificate/fingerprint.go index 382d76b5..e287a792 100644 --- a/command/certificate/fingerprint.go +++ b/command/certificate/fingerprint.go @@ -79,7 +79,7 @@ authenticity of the remote server. debugging invalid certificates remotely.`, }, flags.ServerName, - command.FingerprintFormatFlag(), + command.FingerprintFormatFlag("hex"), }, } } @@ -99,7 +99,7 @@ func fingerprintAction(ctx *cli.Context) error { format = ctx.String("format") ) - encoding, err := command.GetFingerprintEncoding(format, "hex") + encoding, err := command.GetFingerprintEncoding(format) if err != nil { return err } diff --git a/command/command.go b/command/command.go index cb71bcf5..5ef81f4b 100644 --- a/command/command.go +++ b/command/command.go @@ -211,28 +211,27 @@ func setEnvVar(c *cli.Command) { } // FingerprintFormatFlag returns a flag for configuring the fingerprint format. -func FingerprintFormatFlag() cli.StringFlag { +func FingerprintFormatFlag(defaultFmt string) cli.StringFlag { return cli.StringFlag{ Name: "format", - Usage: `The of the fingerprint, it must be "hex", "base64", "base64-url", "base64-raw", or "emoji".`, + Usage: `The of the fingerprint, it must be "hex", "base64", "base64-url", "base64-raw", "base64-url-raw" or "emoji".`, + Value: defaultFmt, } } // GetFingerprintEncoding gets the fingerprint encoding from the format flag. -func GetFingerprintEncoding(format, defaultFmt string) (fingerprint.Encoding, error) { - if format == "" { - format = defaultFmt - } - +func GetFingerprintEncoding(format string) (fingerprint.Encoding, error) { switch strings.ToLower(strings.TrimSpace(format)) { case "hex", "": return fingerprint.HexFingerprint, nil case "base64": - return fingerprint.Base64Fingerprint, nil + return fingerprint.Base64StdFingerprint, nil case "base64url", "base64-url": return fingerprint.Base64URLFingerprint, nil + case "base64urlraw", "base64url-raw", "base64-url-raw": + return fingerprint.Base64RawURLFingerprint, nil case "base64raw", "base64-raw": - return fingerprint.Base64RawFingerprint, nil + return fingerprint.Base64RawStdFingerprint, nil case "emoji", "emojisum": return fingerprint.EmojiFingerprint, nil default: diff --git a/command/command_test.go b/command/command_test.go index 52497bef..6e43cac6 100644 --- a/command/command_test.go +++ b/command/command_test.go @@ -29,7 +29,7 @@ func TestGetFingerprintEncoding(t *testing.T) { args{ "base64", }, - fingerprint.Base64Fingerprint, + fingerprint.Base64StdFingerprint, false, }, { @@ -53,7 +53,7 @@ func TestGetFingerprintEncoding(t *testing.T) { args{ "base64raw", }, - fingerprint.Base64RawFingerprint, + fingerprint.Base64RawStdFingerprint, false, }, { @@ -61,7 +61,31 @@ func TestGetFingerprintEncoding(t *testing.T) { args{ "base64-raw", }, - fingerprint.Base64RawFingerprint, + fingerprint.Base64RawStdFingerprint, + false, + }, + { + "base64urlraw", + args{ + "base64urlraw", + }, + fingerprint.Base64RawURLFingerprint, + false, + }, + { + "base64url-raw", + args{ + "base64url-raw", + }, + fingerprint.Base64RawURLFingerprint, + false, + }, + { + "base64-url-raw", + args{ + "base64-url-raw", + }, + fingerprint.Base64RawURLFingerprint, false, }, { @@ -91,7 +115,7 @@ func TestGetFingerprintEncoding(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := GetFingerprintEncoding(tt.args.format, "hex") + got, err := GetFingerprintEncoding(tt.args.format) if (err != nil) != tt.wantErr { t.Errorf("GetFingerprintEncoding() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/command/crypto/key/fingerprint.go b/command/crypto/key/fingerprint.go index c7f629a3..42b25831 100644 --- a/command/crypto/key/fingerprint.go +++ b/command/crypto/key/fingerprint.go @@ -10,11 +10,12 @@ import ( "os" "github.com/pkg/errors" + "github.com/smallstep/cli/command" "github.com/smallstep/cli/crypto/fingerprint" "github.com/smallstep/cli/crypto/pemutil" "github.com/smallstep/cli/utils" "github.com/urfave/cli" - "go.step.sm/cli-utils/command" + libcommand "go.step.sm/cli-utils/command" "go.step.sm/cli-utils/errs" "golang.org/x/crypto/ssh" ) @@ -22,7 +23,7 @@ import ( func fingerprintCommand() cli.Command { return cli.Command{ Name: "fingerprint", - Action: command.ActionFunc(fingerprintAction), + Action: libcommand.ActionFunc(fingerprintAction), Usage: `print the fingerprint of a public key`, UsageText: `**step crypto key fingerprint** `, Description: `**step crypto key fingerprint** prints the fingerprint of a public key. The @@ -101,7 +102,7 @@ $ step crypto key fingerprint --password-file pass.txt priv.pem Name: "raw", Usage: "Print the raw bytes instead of the fingerprint. These bytes can be piped to a different hash command.", }, - command.FingerprintFormatFlag(), + command.FingerprintFormatFlag(""), }, } } @@ -138,7 +139,12 @@ func fingerprintAction(ctx *cli.Context) error { prefix = "SHA1:" hash = crypto.SHA1 } - encoding, err := command.GetFingerprintEncoding(format, defaultFmt) + + if format == "" { + format = defaultFmt + } + + encoding, err := command.GetFingerprintEncoding(format) if err != nil { return err } diff --git a/command/ssh/fingerprint.go b/command/ssh/fingerprint.go index b2d6d163..a4b8f575 100644 --- a/command/ssh/fingerprint.go +++ b/command/ssh/fingerprint.go @@ -3,18 +3,19 @@ package ssh import ( "fmt" + "github.com/smallstep/cli/command" libfingerprint "github.com/smallstep/cli/crypto/fingerprint" "github.com/smallstep/cli/crypto/sshutil" "github.com/smallstep/cli/utils" "github.com/urfave/cli" - "go.step.sm/cli-utils/command" + libcommand "go.step.sm/cli-utils/command" "go.step.sm/cli-utils/errs" ) func fingerPrintCommand() cli.Command { return cli.Command{ Name: "fingerprint", - Action: command.ActionFunc(fingerprint), + Action: libcommand.ActionFunc(fingerprint), Usage: "print the fingerprint of an SSH public key or certificate", UsageText: `**step ssh fingerprint** `, Description: `**step ssh fingerprint** prints the fingerprint of an ssh public key or @@ -37,7 +38,7 @@ Print the fingerprint for an SSH public key: $ step ssh fingerprint id_ecdsa.pub '''`, Flags: []cli.Flag{ - command.FingerprintFormatFlag(), + command.FingerprintFormatFlag("base64-raw"), }, } } @@ -54,7 +55,7 @@ func fingerprint(ctx *cli.Context) error { ) if format != "" { - encoding, err := command.GetFingerprintEncoding(format, "hex") + encoding, err := command.GetFingerprintEncoding(format) if err != nil { return err } diff --git a/crypto/fingerprint/emoji.go b/crypto/fingerprint/emoji.go index 6acfbb79..b45975d8 100644 --- a/crypto/fingerprint/emoji.go +++ b/crypto/fingerprint/emoji.go @@ -12,8 +12,8 @@ func toEmoji(input []byte) string { // emojiCodeMap is a mapping from byte to emoji. // -// The mapping is based on https://github.com/emojisum/emojisum with amendments -// proposed in https://github.com/emojisum/emojisum/issues/37. +// The mapping is based on draft+2 of https://github.com/emojisum/emojisum. +// (see: https://github.com/emojisum/emojisum/releases/tag/draft%2B2) var emojiCodeMap = []string{ "\U0001f44d", // ๐Ÿ‘ :+1: "\U0001f3b1", // ๐ŸŽฑ :8ball: diff --git a/crypto/fingerprint/fingerprint.go b/crypto/fingerprint/fingerprint.go index 8ca01522..670fdaa5 100644 --- a/crypto/fingerprint/fingerprint.go +++ b/crypto/fingerprint/fingerprint.go @@ -15,12 +15,14 @@ type Encoding int const ( // HexFingerprint represents the hex encoding of the fingerprint. HexFingerprint Encoding = iota - // Base64Fingerprint represents the base64 encoding of the fingerprint. - Base64Fingerprint + // Base64StdFingerprint represents the base64 encoding of the fingerprint. + Base64StdFingerprint // Base64URLFingerprint represents the base64URL encoding of the fingerprint. Base64URLFingerprint - // Base64RawFingerprint represents the base64Raw encoding of the fingerprint. - Base64RawFingerprint + // Base64RawStdFingerprint represents the base64RawStd encoding of the fingerprint. + Base64RawStdFingerprint + // Base64RawURLFingerprint represents the base64RawURL encoding of the fingerprint. + Base64RawURLFingerprint // EmojiFingerprint represents the emoji encoding of the fingerprint. EmojiFingerprint ) @@ -88,12 +90,14 @@ func encode(input []byte, encoding Encoding) string { switch encoding { case HexFingerprint: return strings.ToLower(hex.EncodeToString(input)) - case Base64Fingerprint: + case Base64StdFingerprint: return base64.StdEncoding.EncodeToString(input) case Base64URLFingerprint: return base64.URLEncoding.EncodeToString(input) - case Base64RawFingerprint: + case Base64RawStdFingerprint: return base64.RawStdEncoding.EncodeToString(input) + case Base64RawURLFingerprint: + return base64.RawURLEncoding.EncodeToString(input) case EmojiFingerprint: return toEmoji(input) default: @@ -112,11 +116,13 @@ func decode(input string, encoding Encoding) ([]byte, error) { switch encoding { case HexFingerprint: return hex.DecodeString(input) - case Base64Fingerprint: + case Base64StdFingerprint: return base64.StdEncoding.DecodeString(input) case Base64URLFingerprint: return base64.URLEncoding.DecodeString(input) - case Base64RawFingerprint: + case Base64RawStdFingerprint: + return base64.RawStdEncoding.DecodeString(input) + case Base64RawURLFingerprint: return base64.RawURLEncoding.DecodeString(input) case EmojiFingerprint: return nil, errors.New("decoding emoji fingerprint not supported") diff --git a/crypto/fingerprint/fingerprint_test.go b/crypto/fingerprint/fingerprint_test.go index 1556e0e3..763d7675 100644 --- a/crypto/fingerprint/fingerprint_test.go +++ b/crypto/fingerprint/fingerprint_test.go @@ -28,13 +28,16 @@ func TestEncodedFingerprint(t *testing.T) { []Option{WithHash(crypto.SHA256), WithEncoding(HexFingerprint)}, }, {"base64", "testdata/ca.der", "aQh1H2gpDUVzrgvjmpjIube31OiypmlLdQmUZiat/pg=", - []Option{WithHash(crypto.SHA256), WithEncoding(Base64Fingerprint)}, + []Option{WithHash(crypto.SHA256), WithEncoding(Base64StdFingerprint)}, }, {"base64url", "testdata/ca.der", "aQh1H2gpDUVzrgvjmpjIube31OiypmlLdQmUZiat_pg=", []Option{WithHash(crypto.SHA256), WithEncoding(Base64URLFingerprint)}, }, {"base64raw", "testdata/ca.der", "aQh1H2gpDUVzrgvjmpjIube31OiypmlLdQmUZiat/pg", - []Option{WithHash(crypto.SHA256), WithEncoding(Base64RawFingerprint)}, + []Option{WithHash(crypto.SHA256), WithEncoding(Base64RawStdFingerprint)}, + }, + {"base64url-raw", "testdata/ca.der", "aQh1H2gpDUVzrgvjmpjIube31OiypmlLdQmUZiat_pg", + []Option{WithHash(crypto.SHA256), WithEncoding(Base64RawURLFingerprint)}, }, {"emoji", "testdata/ca.der", "๐Ÿš๐ŸŽ๐Ÿ‘บ๐ŸšŒ๐Ÿฎโ˜๏ธ๐ŸŽ๐Ÿ‘€๐Ÿ‡ฎ๐Ÿ‡นโœ‹๐Ÿผ๐Ÿšฝโ›…๐Ÿผ๐Ÿšฌ๐ŸŽ…๐Ÿ‡ท๐Ÿ‡บ๐Ÿ‡ท๐Ÿ‡บ๐Ÿš‚๐Ÿคข๐ŸŽ€๐Ÿ’ฉ๐Ÿš๐ŸŽ†๐Ÿ‘บ๐ŸŽจ๐Ÿ‘Œโœ”๏ธ๐Ÿšธ๐ŸŒˆโšก๐Ÿผ", []Option{WithHash(crypto.SHA256), WithEncoding(EmojiFingerprint)}, @@ -44,13 +47,16 @@ func TestEncodedFingerprint(t *testing.T) { []Option{WithHash(crypto.SHA256), WithEncoding(HexFingerprint), WithPrefix("PREFIX:")}, }, {"prefix, base64", "testdata/ca.der", "PREFIX:aQh1H2gpDUVzrgvjmpjIube31OiypmlLdQmUZiat/pg=", - []Option{WithHash(crypto.SHA256), WithEncoding(Base64Fingerprint), WithPrefix("PREFIX:")}, + []Option{WithHash(crypto.SHA256), WithEncoding(Base64StdFingerprint), WithPrefix("PREFIX:")}, }, {"prefix, base64url", "testdata/ca.der", "PREFIX:aQh1H2gpDUVzrgvjmpjIube31OiypmlLdQmUZiat_pg=", []Option{WithHash(crypto.SHA256), WithEncoding(Base64URLFingerprint), WithPrefix("PREFIX:")}, }, + {"prefix, base64url-raw", "testdata/ca.der", "PREFIX:aQh1H2gpDUVzrgvjmpjIube31OiypmlLdQmUZiat_pg", + []Option{WithHash(crypto.SHA256), WithEncoding(Base64RawURLFingerprint), WithPrefix("PREFIX:")}, + }, {"prefix, base64raw", "testdata/ca.der", "PREFIX:aQh1H2gpDUVzrgvjmpjIube31OiypmlLdQmUZiat/pg", - []Option{WithHash(crypto.SHA256), WithEncoding(Base64RawFingerprint), WithPrefix("PREFIX:")}, + []Option{WithHash(crypto.SHA256), WithEncoding(Base64RawStdFingerprint), WithPrefix("PREFIX:")}, }, {"prefix, emoji", "testdata/ca.der", "PREFIX:๐Ÿš๐ŸŽ๐Ÿ‘บ๐ŸšŒ๐Ÿฎโ˜๏ธ๐ŸŽ๐Ÿ‘€๐Ÿ‡ฎ๐Ÿ‡นโœ‹๐Ÿผ๐Ÿšฝโ›…๐Ÿผ๐Ÿšฌ๐ŸŽ…๐Ÿ‡ท๐Ÿ‡บ๐Ÿ‡ท๐Ÿ‡บ๐Ÿš‚๐Ÿคข๐ŸŽ€๐Ÿ’ฉ๐Ÿš๐ŸŽ†๐Ÿ‘บ๐ŸŽจ๐Ÿ‘Œโœ”๏ธ๐Ÿšธ๐ŸŒˆโšก๐Ÿผ", []Option{WithHash(crypto.SHA256), WithEncoding(EmojiFingerprint), WithPrefix("PREFIX:")}, diff --git a/crypto/sshutil/fingerprint.go b/crypto/sshutil/fingerprint.go index 8074dd2f..f4bba7d8 100644 --- a/crypto/sshutil/fingerprint.go +++ b/crypto/sshutil/fingerprint.go @@ -53,8 +53,8 @@ func Fingerprint(in []byte, opts ...FingerprintOption) (string, error) { } fp := ssh.FingerprintSHA256(key) - if o.FingerprintOptions != nil { - raw, err := fingerprint.Decode(fp, fingerprint.WithPrefix("SHA256:"), fingerprint.WithEncoding(fingerprint.Base64RawFingerprint)) + if len(o.FingerprintOptions) != 0 { + raw, err := fingerprint.Decode(fp, fingerprint.WithPrefix("SHA256:"), fingerprint.WithEncoding(fingerprint.Base64RawStdFingerprint)) if err != nil { return "", errors.Wrap(err, "decoding fingerprint") } diff --git a/crypto/x509util/crt.go b/crypto/x509util/crt.go index 4453169e..377d79ca 100644 --- a/crypto/x509util/crt.go +++ b/crypto/x509util/crt.go @@ -27,11 +27,13 @@ const ( // HexFingerprint represents hex encoding of fingerprint. HexFingerprint = FingerprintEncoding(fingerprint.HexFingerprint) // Base64Fingerprint represents base64 encoding of fingerprint. - Base64Fingerprint = FingerprintEncoding(fingerprint.Base64Fingerprint) + Base64Fingerprint = FingerprintEncoding(fingerprint.Base64StdFingerprint) // Base64URLFingerprint represents base64URL encoding of fingerprint. Base64URLFingerprint = FingerprintEncoding(fingerprint.Base64URLFingerprint) - // Base64RawFingerprint represents base64Raw encoding of fingerprint. - Base64RawFingerprint = FingerprintEncoding(fingerprint.Base64RawFingerprint) + // Base64RawURLFingerprint represents base64Raw encoding of fingerprint. + Base64RawURLFingerprint = FingerprintEncoding(fingerprint.Base64RawURLFingerprint) + // Base64RawStdFingerprint represents base64Raw encoding of fingerprint. + Base64RawStdFingerprint = FingerprintEncoding(fingerprint.Base64RawStdFingerprint) // EmojiFingerprint represents emoji encoding of fingerprint. EmojiFingerprint = FingerprintEncoding(fingerprint.EmojiFingerprint) ) diff --git a/crypto/x509util/crt_test.go b/crypto/x509util/crt_test.go index 39a2b1ec..e07a4415 100644 --- a/crypto/x509util/crt_test.go +++ b/crypto/x509util/crt_test.go @@ -39,7 +39,8 @@ func TestEncodedFingerprint(t *testing.T) { {"hex", "test_files/ca.crt", HexFingerprint, "6908751f68290d4573ae0be39a98c8b9b7b7d4e8b2a6694b7509946626adfe98"}, {"base64", "test_files/ca.crt", Base64Fingerprint, "aQh1H2gpDUVzrgvjmpjIube31OiypmlLdQmUZiat/pg="}, {"base64url", "test_files/ca.crt", Base64URLFingerprint, "aQh1H2gpDUVzrgvjmpjIube31OiypmlLdQmUZiat_pg="}, - {"base64raw", "test_files/ca.crt", Base64RawFingerprint, "aQh1H2gpDUVzrgvjmpjIube31OiypmlLdQmUZiat/pg"}, + {"base64raw", "test_files/ca.crt", Base64RawStdFingerprint, "aQh1H2gpDUVzrgvjmpjIube31OiypmlLdQmUZiat/pg"}, + {"base64raw", "test_files/ca.crt", Base64RawURLFingerprint, "aQh1H2gpDUVzrgvjmpjIube31OiypmlLdQmUZiat_pg"}, {"emoji", "test_files/ca.crt", EmojiFingerprint, "๐Ÿš๐ŸŽ๐Ÿ‘บ๐ŸšŒ๐Ÿฎโ˜๏ธ๐ŸŽ๐Ÿ‘€๐Ÿ‡ฎ๐Ÿ‡นโœ‹๐Ÿผ๐Ÿšฝโ›…๐Ÿผ๐Ÿšฌ๐ŸŽ…๐Ÿ‡ท๐Ÿ‡บ๐Ÿ‡ท๐Ÿ‡บ๐Ÿš‚๐Ÿคข๐ŸŽ€๐Ÿ’ฉ๐Ÿš๐ŸŽ†๐Ÿ‘บ๐ŸŽจ๐Ÿ‘Œโœ”๏ธ๐Ÿšธ๐ŸŒˆโšก๐Ÿผ"}, } for _, tt := range tests {