1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package p11token
18
19 import (
20 "bytes"
21 "crypto"
22 "crypto/x509"
23 "encoding/base64"
24 "errors"
25 "fmt"
26 "io"
27 "strings"
28
29 "github.com/miekg/pkcs11"
30 "github.com/sassoftware/relic/lib/x509tools"
31 "github.com/sassoftware/relic/token"
32 )
33
34 var classNames = map[uint]string{
35 pkcs11.CKO_DATA: "data",
36 pkcs11.CKO_CERTIFICATE: "certificate",
37 pkcs11.CKO_PUBLIC_KEY: "public_key",
38 pkcs11.CKO_PRIVATE_KEY: "private_key",
39 pkcs11.CKO_SECRET_KEY: "secret_key",
40 pkcs11.CKO_HW_FEATURE: "hw_feature",
41 pkcs11.CKO_DOMAIN_PARAMETERS: "domain_parameters",
42 pkcs11.CKO_MECHANISM: "mechanism",
43 pkcs11.CKO_OTP_KEY: "otp_key",
44 }
45
46 var keyTypes = map[uint]string{
47 pkcs11.CKK_RSA: "rsa",
48 pkcs11.CKK_DSA: "dsa",
49 pkcs11.CKK_EC: "ec",
50 }
51
52 func (tok *Token) ListKeys(opts token.ListOptions) error {
53 filterKeyId, err := parseKeyID(opts.ID)
54 if err != nil {
55 return errors.New("invalid filter id")
56 }
57 tok.mutex.Lock()
58 defer tok.mutex.Unlock()
59 if err := tok.ctx.FindObjectsInit(tok.sh, nil); err != nil {
60 return err
61 }
62 defer tok.ctx.FindObjectsFinal(tok.sh)
63 for {
64 objects, _, err := tok.ctx.FindObjects(tok.sh, 1)
65 if err != nil {
66 return err
67 } else if len(objects) == 0 {
68 break
69 }
70 for _, handle := range objects {
71 objId := tok.getAttribute(handle, pkcs11.CKA_ID)
72 label := tok.getAttribute(handle, pkcs11.CKA_LABEL)
73 if opts.Label != "" && string(label) != opts.Label {
74 continue
75 }
76 if len(filterKeyId) != 0 && !bytes.Equal(filterKeyId, objId) {
77 continue
78 }
79 fmt.Fprintf(opts.Output, "handle 0x%08x:\n", handle)
80 class := attrToInt(tok.getAttribute(handle, pkcs11.CKA_CLASS))
81 if name := classNames[class]; name != "" {
82 fmt.Fprintf(opts.Output, " class: %s\n", name)
83 } else {
84 fmt.Fprintf(opts.Output, " class: 0x%08x\n", class)
85 }
86 if len(objId) > 0 {
87 fmt.Fprintf(opts.Output, " id: %s\n", formatKeyID(objId))
88 }
89 if len(label) > 0 {
90 fmt.Fprintf(opts.Output, " label: %s\n", label)
91 }
92 switch class {
93 case pkcs11.CKO_PUBLIC_KEY:
94 tok.printKey(opts, handle)
95 case pkcs11.CKO_PRIVATE_KEY:
96 tok.printKey(opts, handle)
97 case pkcs11.CKO_CERTIFICATE:
98 tok.printCertificate(opts, handle)
99 case pkcs11.CKO_DATA:
100 value := tok.getAttribute(handle, pkcs11.CKA_VALUE)
101 fmt.Fprintf(opts.Output, " size: %d\n", len(value))
102 if opts.Values {
103 fmt.Fprintln(opts.Output, " value: !!binary |")
104 dumpData(opts.Output, value)
105 }
106 }
107 fmt.Fprintln(opts.Output)
108 }
109 }
110 return nil
111 }
112
113 func (tok *Token) printKey(opts token.ListOptions, handle pkcs11.ObjectHandle) {
114 keyType := attrToInt(tok.getAttribute(handle, pkcs11.CKA_KEY_TYPE))
115 if name := keyTypes[keyType]; name != "" {
116 fmt.Fprintf(opts.Output, " type: %s\n", name)
117 } else {
118 fmt.Fprintf(opts.Output, " type: 0x%08x\n", keyType)
119 }
120 switch keyType {
121 case pkcs11.CKK_RSA:
122 if n := tok.getAttribute(handle, pkcs11.CKA_MODULUS); len(n) != 0 {
123 fmt.Fprintf(opts.Output, " bits: %d\n", len(n)*8)
124 if opts.Values {
125 fmt.Fprintf(opts.Output, " n: 0x%x\n", bytesToBig(n))
126 }
127 }
128 if e := tok.getAttribute(handle, pkcs11.CKA_PUBLIC_EXPONENT); len(e) != 0 && opts.Values {
129 fmt.Fprintf(opts.Output, " e: %s\n", bytesToBig(e))
130 }
131 case pkcs11.CKK_EC:
132 ecparams := tok.getAttribute(handle, pkcs11.CKA_EC_PARAMS)
133 if len(ecparams) == 0 {
134 return
135 }
136 curve, err := x509tools.CurveByDer(ecparams)
137 if err != nil {
138 fmt.Fprintf(opts.Output, " curve: %x\n", ecparams)
139 return
140 }
141 fmt.Fprintf(opts.Output, " bits: %d\n", curve.Bits)
142 ecpoint := tok.getAttribute(handle, pkcs11.CKA_EC_POINT)
143 if len(ecpoint) > 0 && opts.Values {
144 x, y := x509tools.DerToPoint(curve.Curve, ecpoint)
145 if x != nil {
146 fmt.Fprintf(opts.Output, " x: 0x%x\n", x)
147 fmt.Fprintf(opts.Output, " y: 0x%x\n", y)
148 }
149 }
150 }
151 }
152
153 func (tok *Token) printCertificate(opts token.ListOptions, handle pkcs11.ObjectHandle) {
154 blob := tok.getAttribute(handle, pkcs11.CKA_VALUE)
155 if len(blob) == 0 {
156 fmt.Fprintln(opts.Output, "certificate is missing")
157 return
158 }
159 cert, err := x509.ParseCertificate(blob)
160 if err != nil {
161 fmt.Fprintln(opts.Output, "certificate is invalid:", err)
162 }
163 d := crypto.SHA1.New()
164 d.Write(blob)
165 fmt.Fprintf(opts.Output, " subject: %s\n issuer: %s\n sha1: %x\n", x509tools.FormatSubject(cert), x509tools.FormatIssuer(cert), d.Sum(nil))
166 if opts.Values {
167 fmt.Fprintln(opts.Output, " value: |\n -----BEGIN CERTIFICATE-----")
168 dumpData(opts.Output, blob)
169 fmt.Fprintln(opts.Output, " -----END CERTIFICATE-----")
170 }
171 }
172
173 func formatKeyID(keyID []byte) string {
174 chunks := make([]string, len(keyID))
175 for i, j := range keyID {
176 chunks[i] = fmt.Sprintf("%02x", j)
177 }
178 return strings.Join(chunks, ":")
179 }
180
181 func dumpData(w io.Writer, d []byte) error {
182 encoded := base64.StdEncoding.EncodeToString(d)
183 for len(encoded) > 0 {
184 n := 64
185 if n > len(encoded) {
186 n = len(encoded)
187 }
188 if _, err := fmt.Fprintln(w, " ", encoded[:n]); err != nil {
189 return err
190 }
191 encoded = encoded[n:]
192 }
193 return nil
194 }
195
View as plain text