1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
package key
import (
"bytes"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
"fmt"
"math/big"
"github.com/pkg/errors"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/crypto/pemutil"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/utils"
"github.com/urfave/cli"
)
func inspectCommand() cli.Command {
return cli.Command{
Name: "inspect",
Action: command.ActionFunc(inspectAction),
Usage: `print key details in human readable format`,
UsageText: `**step crypto key inspect** <key-file>`,
Description: `**step crypto key inspect** prints details of a public or a private key in a
human readable format the public key corresponding to the given <key-file>.
## POSITIONAL ARGUMENTS
<key-file>
: Path to a public or private key.
## EXAMPLES
Print details of the given key:
'''
$ step crypto key inspect priv.pem
'''
## NOTES
This command shows the raw parameters of the keys, it does not include headers
that the marshaled version of the keys might have. For example, a marshaled
version an EC public key will have 0x04 in the first byte to indicate the
uncompressed form specified in section 4.3.6 of ANSI X9.62.`,
Flags: []cli.Flag{
cli.StringFlag{
Name: "password-file",
Usage: "The path to the <file> containing passphrase to decrypt private key.",
},
},
}
}
func inspectAction(ctx *cli.Context) error {
if err := errs.MinMaxNumberOfArguments(ctx, 0, 1); err != nil {
return err
}
var name string
switch ctx.NArg() {
case 0:
name = "-"
case 1:
name = ctx.Args().First()
default:
return errs.TooManyArguments(ctx)
}
b, err := utils.ReadFile(name)
if err != nil {
return err
}
var key interface{}
switch {
case bytes.HasPrefix(b, []byte("-----BEGIN ")):
opts := []pemutil.Options{
pemutil.WithFilename(name),
pemutil.WithFirstBlock(),
}
if passFile := ctx.String("password-file"); passFile != "" {
opts = append(opts, pemutil.WithPasswordFile(passFile))
}
if key, err = pemutil.ParseKey(b, opts...); err != nil {
return err
}
case isSSHPublicKey(b):
if key, err = pemutil.ParseSSH(b); err != nil {
return err
}
case isJWK(b):
if key, err = parseJWK(ctx, b); err != nil {
return err
}
default: // assume DER format
if key, err = pemutil.ParseDER(b); err != nil {
return err
}
}
switch k := key.(type) {
case *rsa.PublicKey:
fmt.Printf("RSA Public-Key: (%d bit)\n", k.Size()*8)
bigIntPaddedPrinter("Modulus", k.N, k.Size())
fmt.Printf("Exponent: %d (0x%x)\n", k.E, k.E)
case *rsa.PrivateKey:
fmt.Printf("RSA Private-Key: (%d bit)\n", k.Size()*8)
bigIntPaddedPrinter("Modulus", k.N, k.Size())
fmt.Printf("Public Exponent: %d (0x%x)\n", k.E, k.E)
bigIntPaddedPrinter("Private Exponent", k.D, k.Size())
for i := range k.Primes {
bigIntPrinter(fmt.Sprintf("Prime #%d", i+1), k.Primes[i])
}
bigIntPrinter("Exponent #1", k.Precomputed.Dp)
bigIntPrinter("Exponent #2", k.Precomputed.Dq)
bigIntPrinter("Coefficient", k.Precomputed.Qinv)
case *ecdsa.PublicKey:
byteLen := (k.Params().BitSize + 7) >> 3
fmt.Printf("EC Public-Key: (%d bit)\n", k.Params().BitSize)
bigIntPaddedPrinter("X", k.X, byteLen)
bigIntPaddedPrinter("Y", k.Y, byteLen)
fmt.Printf("Curve: %s\n", k.Params().Name)
case *ecdsa.PrivateKey:
byteLen := (k.Params().BitSize + 7) >> 3
fmt.Printf("EC PrivateKey-Key: (%d bit)\n", k.Params().BitSize)
bigIntPaddedPrinter("X", k.X, byteLen)
bigIntPaddedPrinter("Y", k.Y, byteLen)
bigIntPaddedPrinter("D", k.D, byteLen)
fmt.Printf("Curve: %s\n", k.Params().Name)
case ed25519.PublicKey:
fmt.Printf("Ed25519 Public-Key: (%d bit)\n", 8*len(k))
bytesPrinter("Public", k)
case ed25519.PrivateKey:
fmt.Printf("Ed25519 Private-Key: (%d bit)\n", 8*len(k))
bytesPrinter("Public", k[32:])
bytesPrinter("Private", k[:32])
default:
return errors.Errorf("unsupported key type '%T'", k)
}
return nil
}
func bigIntPrinter(name string, val *big.Int) {
bytesPrinter(name, val.Bytes())
}
func bigIntPaddedPrinter(name string, val *big.Int, size int) {
bytesPrinter(name, paddedBytes(val.Bytes(), size))
}
func bytesPrinter(name string, bytes []byte) {
fmt.Print(name + ":")
for i, b := range bytes {
if (i % 16) == 0 {
fmt.Print("\n ")
}
fmt.Printf("%02x", b)
if i != len(bytes)-1 {
fmt.Print(":")
}
}
fmt.Println()
}
func paddedBytes(b []byte, size int) []byte {
ret := make([]byte, size)
copy(ret[len(ret)-len(b):], b)
return ret
}
|