-
Notifications
You must be signed in to change notification settings - Fork 247
/
inspect.go
168 lines (149 loc) · 3.99 KB
/
inspect.go
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
package ssh
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"os"
"github.com/pkg/errors"
"github.com/smallstep/cli/internal/sshutil"
"github.com/smallstep/cli/utils"
"github.com/urfave/cli"
"go.step.sm/cli-utils/command"
"go.step.sm/cli-utils/errs"
"golang.org/x/crypto/ssh"
)
func inspectCommand() cli.Command {
return cli.Command{
Name: "inspect",
Action: command.ActionFunc(inspectAction),
Usage: "print the contents of an ssh certificate",
UsageText: `**step ssh inspect** <crt-file>`,
Description: `**step ssh inspect** command prints ssh certificate details in human readable
format.
## POSITIONAL ARGUMENTS
<crt-file>
: The path to an ssh certificate.
## EXAMPLES
Prints the contents of id_ecdsa-cert.pub:
'''
$ step ssh inspect id_ecdsa-cert.pub
'''`,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Value: "text",
Usage: `The output format for printing the introspection details.
: <format> is a string and must be one of:
**text**
: Print output in unstructured text suitable for a human to read.
**json**
: Print output in JSON format.`,
},
},
}
}
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)
}
var (
format = ctx.String("format")
)
if format != "text" && format != "json" {
return errs.InvalidFlagValue(ctx, "format", format, "text, json")
}
b, err := utils.ReadFile(name)
if err != nil {
return err
}
pub, _, _, _, err := ssh.ParseAuthorizedKey(b)
if err != nil {
// Attempt to parse the key without the type.
b = bytes.TrimSpace(b)
keyBytes := make([]byte, base64.StdEncoding.DecodedLen(len(b)))
n, err := base64.StdEncoding.Decode(keyBytes, b)
if err != nil {
return errors.Wrap(err, "error parsing ssh certificate")
}
if pub, err = ssh.ParsePublicKey(keyBytes[:n]); err != nil {
return errors.Wrap(err, "error parsing ssh certificate")
}
}
cert, ok := pub.(*ssh.Certificate)
if !ok {
return errors.Errorf("error decoding ssh certificate: %T is not an *ssh.Certificate", pub)
}
inspect, err := sshutil.InspectCertificate(cert)
if err != nil {
return err
}
switch format {
case "text":
space := ""
fmt.Println(name + ":")
fmt.Printf("%8sType: %s %s certificate\n", space, inspect.KeyName, inspect.Type)
fmt.Printf("%8sPublic key: %s-CERT %s\n", space, inspect.KeyAlgo, inspect.KeyFingerprint)
fmt.Printf("%8sSigning CA: %s %s (using %s)\n", space, inspect.SigningKeyAlgo, inspect.SigningKeyFingerprint, inspect.Signature.Type)
fmt.Printf("%8sKey ID: \"%s\"\n", space, inspect.KeyID)
fmt.Printf("%8sSerial: %d\n", space, inspect.Serial)
fmt.Printf("%8sValid: %s\n", space, inspect.Validity())
fmt.Printf("%8sPrincipals: ", space)
if len(inspect.Principals) == 0 {
fmt.Println("(none)")
} else {
fmt.Println()
for _, p := range inspect.Principals {
fmt.Printf("%16s%s\n", space, p)
}
}
fmt.Printf("%8sCritical Options: ", space)
if len(inspect.CriticalOptions) == 0 {
fmt.Println("(none)")
} else {
fmt.Println()
for k, v := range inspect.CriticalOptions {
fmt.Printf("%16s%s %v\n", space, k, v)
}
}
fmt.Printf("%8sExtensions: ", space)
if len(inspect.Extensions) == 0 {
fmt.Println("(none)")
} else {
fmt.Println()
for k, v := range inspect.Extensions {
fmt.Printf("%16s%s %v\n", space, k, v)
}
}
fmt.Printf("%8sSignature:", space)
for i, b := range cert.Signature.Blob {
if (i % 16) == 0 {
fmt.Printf("\n%16s", space)
}
fmt.Printf("%02x", b)
if i != len(cert.Signature.Blob)-1 {
fmt.Print(":")
}
}
fmt.Println()
case "json":
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
err := enc.Encode(inspect)
if err != nil {
return errors.WithStack(err)
}
default:
return errs.InvalidFlagValue(ctx, "format", format, "text, json")
}
return nil
}