1: /*
2: * Copyright (C) 2009 Martin Willi
3: * Copyright (C) 2017 Andreas Steffen
4: * HSR Hochschule fuer Technik Rapperswil
5: *
6: * This program is free software; you can redistribute it and/or modify it
7: * under the terms of the GNU General Public License as published by the
8: * Free Software Foundation; either version 2 of the License, or (at your
9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10: *
11: * This program is distributed in the hope that it will be useful, but
12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14: * for more details.
15: */
16:
17: #include <errno.h>
18:
19: #include "pki.h"
20:
21: #include <credentials/certificates/certificate.h>
22: #include <credentials/certificates/x509.h>
23:
24: typedef enum {
25: FORMAT_PRETTY,
26: FORMAT_HEX,
27: FORMAT_BASE64,
28: FORMAT_BINARY,
29: } format_t;
30:
31: /**
32: * Print a single keyid in the requested format
33: */
34: static bool print_id(chunk_t id, format_t format, char *desc)
35: {
36: chunk_t chunk;
37:
38: switch (format)
39: {
40: case FORMAT_PRETTY:
41: printf("%s:\n %#B\n", desc, &id);
42: break;
43: case FORMAT_HEX:
44: chunk = chunk_to_hex(id, NULL, FALSE);
45: printf("%.*s\n", (int)chunk.len, chunk.ptr);
46: chunk_free(&chunk);
47: break;
48: case FORMAT_BASE64:
49: chunk = chunk_to_base64(id, NULL);
50: printf("%.*s\n", (int)chunk.len, chunk.ptr);
51: chunk_free(&chunk);
52: break;
53: case FORMAT_BINARY:
54: if (fwrite(id.ptr, id.len, 1, stdout) != 1)
55: {
56: fprintf(stderr, "writing %s failed\n", desc);
57: return FALSE;
58: }
59: break;
60: }
61: return TRUE;
62: }
63:
64: /**
65: * Calculate the keyid of a key/certificate
66: */
67: static int keyid()
68: {
69: credential_type_t type = CRED_PRIVATE_KEY;
70: int subtype = KEY_ANY;
71: certificate_t *cert;
72: private_key_t *private;
73: public_key_t *public;
74: format_t format = FORMAT_PRETTY;
75: enum {
76: ID_TYPE_ALL,
77: ID_TYPE_SPK,
78: ID_TYPE_SPKI,
79: } id_type = FORMAT_PRETTY;
80: char *file = NULL, *keyid = NULL;
81: void *cred;
82: chunk_t id, spk = chunk_empty, spki = chunk_empty;
83: char *arg;
84:
85: while (TRUE)
86: {
87: switch (command_getopt(&arg))
88: {
89: case 'h':
90: return command_usage(NULL);
91: case 't':
92: if (streq(arg, "rsa") ||
93: streq(arg, "rsa-priv"))
94: {
95: type = CRED_PRIVATE_KEY;
96: subtype = KEY_RSA;
97: }
98: else if (streq(arg, "ecdsa") ||
99: streq(arg, "ecdsa-priv"))
100: {
101: type = CRED_PRIVATE_KEY;
102: subtype = KEY_ECDSA;
103: }
104: else if (streq(arg, "bliss") ||
105: streq(arg, "bliss-priv"))
106: {
107: type = CRED_PRIVATE_KEY;
108: subtype = KEY_BLISS;
109: }
110: else if (streq(arg, "priv"))
111: {
112: type = CRED_PRIVATE_KEY;
113: subtype = KEY_ANY;
114: }
115: else if (streq(arg, "pub"))
116: {
117: type = CRED_PUBLIC_KEY;
118: subtype = KEY_ANY;
119: }
120: else if (streq(arg, "pkcs10"))
121: {
122: type = CRED_CERTIFICATE;
123: subtype = CERT_PKCS10_REQUEST;
124: }
125: else if (streq(arg, "x509"))
126: {
127: type = CRED_CERTIFICATE;
128: subtype = CERT_X509;
129: }
130: else
131: {
132: return command_usage( "invalid input type");
133: }
134: continue;
135: case 'I':
136: if (streq(arg, "spk"))
137: {
138: id_type = ID_TYPE_SPK;
139: }
140: else if (streq(arg, "spki"))
141: {
142: id_type = ID_TYPE_SPKI;
143: }
144: else if (!streq(arg, "all"))
145: {
146: return command_usage( "invalid id type");
147: }
148: continue;
149: case 'f':
150: if (streq(arg, "hex"))
151: {
152: format = FORMAT_HEX;
153: }
154: else if (streq(arg, "base64"))
155: {
156: format = FORMAT_BASE64;
157: }
158: else if (streq(arg, "bin"))
159: {
160: format = FORMAT_BINARY;
161: }
162: else if (!streq(arg, "pretty"))
163: {
164: return command_usage( "invalid output format");
165: }
166: continue;
167: case 'i':
168: file = arg;
169: continue;
170: case 'x':
171: keyid = arg;
172: continue;
173: case EOF:
174: break;
175: default:
176: return command_usage("invalid --keyid option");
177: }
178: break;
179: }
180: if (file)
181: {
182: cred = lib->creds->create(lib->creds, type, subtype,
183: BUILD_FROM_FILE, file, BUILD_END);
184: }
185: else if (keyid)
186: {
187: chunk_t chunk;
188:
189: chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
190: cred = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
191: BUILD_PKCS11_KEYID, chunk, BUILD_END);
192: free(chunk.ptr);
193: }
194: else
195: {
196: chunk_t chunk;
197:
198: set_file_mode(stdin, CERT_ASN1_DER);
199: if (!chunk_from_fd(0, &chunk))
200: {
201: fprintf(stderr, "reading input failed: %s\n", strerror(errno));
202: return 1;
203: }
204: cred = lib->creds->create(lib->creds, type, subtype,
205: BUILD_BLOB, chunk, BUILD_END);
206: free(chunk.ptr);
207: }
208: if (!cred)
209: {
210: fprintf(stderr, "parsing input failed\n");
211: return 1;
212: }
213:
214: if (type == CRED_PRIVATE_KEY)
215: {
216: private = cred;
217: if (private->get_fingerprint(private, KEYID_PUBKEY_SHA1, &id))
218: {
219: spk = chunk_clone(id);
220: }
221: if (private->get_fingerprint(private, KEYID_PUBKEY_INFO_SHA1, &id))
222: {
223: spki = chunk_clone(id);
224: }
225: private->destroy(private);
226: }
227: else if (type == CRED_PUBLIC_KEY)
228: {
229: public = cred;
230: if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &id))
231: {
232: spk = chunk_clone(id);
233: }
234: if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &id))
235: {
236: spki = chunk_clone(id);
237: }
238: public->destroy(public);
239: }
240: else
241: {
242: cert = cred;
243: public = cert->get_public_key(cert);
244: if (!public)
245: {
246: fprintf(stderr, "extracting public key from certificate failed");
247: return 1;
248: }
249: if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &id))
250: {
251: spk = chunk_clone(id);
252: }
253: if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &id))
254: {
255: spki = chunk_clone(id);
256: }
257: public->destroy(public);
258: cert->destroy(cert);
259: }
260:
261: if (id_type == ID_TYPE_ALL || id_type == ID_TYPE_SPK)
262: {
263: if (!spk.len ||
264: !print_id(spk, format, "subjkey (SHA-1 of subjectPublicKey)"))
265: {
266: return 1;
267: }
268: }
269: if (id_type == ID_TYPE_ALL || id_type == ID_TYPE_SPKI)
270: {
271: if (!spki.len ||
272: !print_id(spki, format, "keyid (SHA-1 of subjectPublicKeyInfo)"))
273: {
274: return 1;
275: }
276: }
277: chunk_free(&spk);
278: chunk_free(&spki);
279: return 0;
280: }
281:
282: /**
283: * Register the command.
284: */
285: static void __attribute__ ((constructor))reg()
286: {
287: command_register((command_t)
288: { keyid, 'k', "keyid",
289: "calculate key identifiers of a key/certificate",
290: {"[--in file|--keyid hex] [--type priv|rsa|ecdsa|bliss|pub|pkcs10|x509]",
291: "[--id all|spk|spki] [--format pretty|hex|base64|bin]"},
292: {
293: {"help", 'h', 0, "show usage information"},
294: {"in", 'i', 1, "input file, default: stdin"},
295: {"keyid", 'x', 1, "smartcard or TPM private key object handle"},
296: {"type", 't', 1, "type of key, default: priv"},
297: {"id", 'I', 1, "type of identifier, default: all"},
298: {"format", 'f', 1, "output format, default: pretty"},
299: }
300: });
301: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>