]>
Commit | Line | Data |
---|---|---|
2e57b212 MW |
1 | /* |
2 | * Copyright (C) 2010 Martin Willi | |
3 | * Copyright (C) 2010 revosec AG | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License as published by the | |
7 | * Free Software Foundation; either version 2 of the License, or (at your | |
8 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
13 | * for more details. | |
14 | */ | |
15 | ||
16 | #include "pki.h" | |
17 | ||
6c3ac044 | 18 | #include <asn1/asn1.h> |
20ea84da | 19 | #include <asn1/oid.h> |
2e57b212 MW |
20 | #include <credentials/certificates/certificate.h> |
21 | #include <credentials/certificates/x509.h> | |
21f80e9d | 22 | #include <credentials/certificates/crl.h> |
20ea84da | 23 | #include <credentials/certificates/ac.h> |
2e57b212 MW |
24 | #include <selectors/traffic_selector.h> |
25 | ||
26 | #include <time.h> | |
1c4a3459 | 27 | #include <errno.h> |
2e57b212 MW |
28 | |
29 | /** | |
30 | * Print public key information | |
31 | */ | |
32 | static void print_pubkey(public_key_t *key) | |
33 | { | |
34 | chunk_t chunk; | |
35 | ||
36 | printf("pubkey: %N %d bits\n", key_type_names, key->get_type(key), | |
a944d209 | 37 | key->get_keysize(key)); |
da9724e6 | 38 | if (key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &chunk)) |
2e57b212 MW |
39 | { |
40 | printf("keyid: %#B\n", &chunk); | |
41 | } | |
da9724e6 | 42 | if (key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &chunk)) |
2e57b212 MW |
43 | { |
44 | printf("subjkey: %#B\n", &chunk); | |
45 | } | |
46 | } | |
47 | ||
48 | /** | |
49 | * Print private key information | |
50 | */ | |
51 | static void print_key(private_key_t *key) | |
52 | { | |
53 | public_key_t *public; | |
54 | ||
55 | public = key->get_public_key(key); | |
56 | if (public) | |
57 | { | |
58 | printf("private key with:\n"); | |
59 | print_pubkey(public); | |
60 | public->destroy(public); | |
61 | } | |
62 | else | |
63 | { | |
64 | printf("extracting public from private key failed\n"); | |
65 | } | |
66 | } | |
67 | ||
68 | /** | |
69 | * Print X509 specific certificate information | |
70 | */ | |
71 | static void print_x509(x509_t *x509) | |
72 | { | |
73 | enumerator_t *enumerator; | |
74 | identification_t *id; | |
75 | traffic_selector_t *block; | |
76 | chunk_t chunk; | |
77 | bool first; | |
78 | char *uri; | |
b3d359e5 | 79 | int len, explicit, inhibit; |
2e57b212 | 80 | x509_flag_t flags; |
a6478a04 | 81 | x509_cdp_t *cdp; |
6c3ac044 | 82 | x509_cert_policy_t *policy; |
3ffc9d9a | 83 | x509_policy_mapping_t *mapping; |
2e57b212 | 84 | |
e464894e | 85 | chunk = chunk_skip_zero(x509->get_serial(x509)); |
2e57b212 MW |
86 | printf("serial: %#B\n", &chunk); |
87 | ||
88 | first = TRUE; | |
89 | enumerator = x509->create_subjectAltName_enumerator(x509); | |
90 | while (enumerator->enumerate(enumerator, &id)) | |
91 | { | |
92 | if (first) | |
93 | { | |
94 | printf("altNames: "); | |
95 | first = FALSE; | |
96 | } | |
97 | else | |
98 | { | |
99 | printf(", "); | |
100 | } | |
101 | printf("%Y", id); | |
102 | } | |
103 | if (!first) | |
104 | { | |
105 | printf("\n"); | |
106 | } | |
107 | enumerator->destroy(enumerator); | |
108 | ||
109 | flags = x509->get_flags(x509); | |
110 | printf("flags: "); | |
111 | if (flags & X509_CA) | |
112 | { | |
113 | printf("CA "); | |
114 | } | |
bb0cda2f MW |
115 | if (flags & X509_CRL_SIGN) |
116 | { | |
117 | printf("CRLSign "); | |
118 | } | |
2e57b212 MW |
119 | if (flags & X509_AA) |
120 | { | |
121 | printf("AA "); | |
122 | } | |
123 | if (flags & X509_OCSP_SIGNER) | |
124 | { | |
125 | printf("OCSP "); | |
126 | } | |
127 | if (flags & X509_AA) | |
128 | { | |
129 | printf("AA "); | |
130 | } | |
131 | if (flags & X509_SERVER_AUTH) | |
132 | { | |
133 | printf("serverAuth "); | |
134 | } | |
135 | if (flags & X509_CLIENT_AUTH) | |
136 | { | |
137 | printf("clientAuth "); | |
138 | } | |
4bc4e8e1 TB |
139 | if (flags & X509_IKE_INTERMEDIATE) |
140 | { | |
141 | printf("iKEIntermediate "); | |
142 | } | |
98ae0492 AS |
143 | if (flags & X509_MS_SMARTCARD_LOGON) |
144 | { | |
145 | printf("msSmartcardLogon "); | |
146 | } | |
2e57b212 MW |
147 | if (flags & X509_SELF_SIGNED) |
148 | { | |
149 | printf("self-signed "); | |
150 | } | |
151 | printf("\n"); | |
152 | ||
153 | first = TRUE; | |
154 | enumerator = x509->create_crl_uri_enumerator(x509); | |
a6478a04 | 155 | while (enumerator->enumerate(enumerator, &cdp)) |
2e57b212 MW |
156 | { |
157 | if (first) | |
158 | { | |
a6478a04 | 159 | printf("CRL URIs: %s", cdp->uri); |
2e57b212 MW |
160 | first = FALSE; |
161 | } | |
162 | else | |
163 | { | |
a6478a04 | 164 | printf(" %s", cdp->uri); |
4e508517 | 165 | } |
a6478a04 | 166 | if (cdp->issuer) |
4e508517 | 167 | { |
a6478a04 | 168 | printf(" (CRL issuer: %Y)", cdp->issuer); |
2e57b212 | 169 | } |
4e508517 | 170 | printf("\n"); |
2e57b212 MW |
171 | } |
172 | enumerator->destroy(enumerator); | |
173 | ||
174 | first = TRUE; | |
175 | enumerator = x509->create_ocsp_uri_enumerator(x509); | |
176 | while (enumerator->enumerate(enumerator, &uri)) | |
177 | { | |
178 | if (first) | |
179 | { | |
180 | printf("OCSP URIs: %s\n", uri); | |
181 | first = FALSE; | |
182 | } | |
183 | else | |
184 | { | |
185 | printf(" %s\n", uri); | |
186 | } | |
187 | } | |
188 | enumerator->destroy(enumerator); | |
189 | ||
b3d359e5 | 190 | len = x509->get_constraint(x509, X509_PATH_LEN); |
5dba5852 | 191 | if (len != X509_NO_CONSTRAINT) |
2e57b212 MW |
192 | { |
193 | printf("pathlen: %d\n", len); | |
194 | } | |
195 | ||
64bcaae2 MW |
196 | first = TRUE; |
197 | enumerator = x509->create_name_constraint_enumerator(x509, TRUE); | |
198 | while (enumerator->enumerate(enumerator, &id)) | |
199 | { | |
200 | if (first) | |
201 | { | |
202 | printf("Permitted NameConstraints:\n"); | |
203 | first = FALSE; | |
204 | } | |
205 | printf(" %Y\n", id); | |
206 | } | |
207 | enumerator->destroy(enumerator); | |
208 | first = TRUE; | |
209 | enumerator = x509->create_name_constraint_enumerator(x509, FALSE); | |
210 | while (enumerator->enumerate(enumerator, &id)) | |
211 | { | |
212 | if (first) | |
213 | { | |
214 | printf("Excluded NameConstraints:\n"); | |
215 | first = FALSE; | |
216 | } | |
217 | printf(" %Y\n", id); | |
218 | } | |
219 | enumerator->destroy(enumerator); | |
220 | ||
6c3ac044 MW |
221 | first = TRUE; |
222 | enumerator = x509->create_cert_policy_enumerator(x509); | |
223 | while (enumerator->enumerate(enumerator, &policy)) | |
224 | { | |
225 | char *oid; | |
226 | ||
227 | if (first) | |
228 | { | |
229 | printf("CertificatePolicies:\n"); | |
230 | first = FALSE; | |
231 | } | |
232 | oid = asn1_oid_to_string(policy->oid); | |
233 | if (oid) | |
234 | { | |
235 | printf(" %s\n", oid); | |
236 | free(oid); | |
237 | } | |
238 | else | |
239 | { | |
240 | printf(" %#B\n", &policy->oid); | |
241 | } | |
242 | if (policy->cps_uri) | |
243 | { | |
244 | printf(" CPS: %s\n", policy->cps_uri); | |
245 | } | |
246 | if (policy->unotice_text) | |
247 | { | |
248 | printf(" Notice: %s\n", policy->unotice_text); | |
249 | ||
250 | } | |
251 | } | |
252 | enumerator->destroy(enumerator); | |
253 | ||
3ffc9d9a MW |
254 | first = TRUE; |
255 | enumerator = x509->create_policy_mapping_enumerator(x509); | |
256 | while (enumerator->enumerate(enumerator, &mapping)) | |
257 | { | |
258 | char *issuer_oid, *subject_oid; | |
259 | ||
260 | if (first) | |
261 | { | |
262 | printf("PolicyMappings:\n"); | |
263 | first = FALSE; | |
264 | } | |
265 | issuer_oid = asn1_oid_to_string(mapping->issuer); | |
266 | subject_oid = asn1_oid_to_string(mapping->subject); | |
267 | printf(" %s => %s\n", issuer_oid, subject_oid); | |
268 | free(issuer_oid); | |
269 | free(subject_oid); | |
270 | } | |
271 | enumerator->destroy(enumerator); | |
272 | ||
b3d359e5 MW |
273 | explicit = x509->get_constraint(x509, X509_REQUIRE_EXPLICIT_POLICY); |
274 | inhibit = x509->get_constraint(x509, X509_INHIBIT_POLICY_MAPPING); | |
6a339fff | 275 | len = x509->get_constraint(x509, X509_INHIBIT_ANY_POLICY); |
b3d359e5 | 276 | |
6a339fff MW |
277 | if (explicit != X509_NO_CONSTRAINT || inhibit != X509_NO_CONSTRAINT || |
278 | len != X509_NO_CONSTRAINT) | |
a864eb37 MW |
279 | { |
280 | printf("PolicyConstraints:\n"); | |
b3d359e5 | 281 | if (explicit != X509_NO_CONSTRAINT) |
a864eb37 | 282 | { |
b3d359e5 | 283 | printf(" requireExplicitPolicy: %d\n", explicit); |
a864eb37 | 284 | } |
b3d359e5 | 285 | if (inhibit != X509_NO_CONSTRAINT) |
a864eb37 | 286 | { |
b3d359e5 | 287 | printf(" inhibitPolicyMapping: %d\n", inhibit); |
a864eb37 | 288 | } |
6a339fff MW |
289 | if (len != X509_NO_CONSTRAINT) |
290 | { | |
291 | printf(" inhibitAnyPolicy: %d\n", len); | |
292 | } | |
a864eb37 MW |
293 | } |
294 | ||
2e57b212 MW |
295 | chunk = x509->get_authKeyIdentifier(x509); |
296 | if (chunk.ptr) | |
297 | { | |
298 | printf("authkeyId: %#B\n", &chunk); | |
299 | } | |
300 | ||
301 | chunk = x509->get_subjectKeyIdentifier(x509); | |
302 | if (chunk.ptr) | |
303 | { | |
304 | printf("subjkeyId: %#B\n", &chunk); | |
305 | } | |
306 | if (x509->get_flags(x509) & X509_IP_ADDR_BLOCKS) | |
307 | { | |
308 | first = TRUE; | |
309 | printf("addresses: "); | |
310 | enumerator = x509->create_ipAddrBlock_enumerator(x509); | |
311 | while (enumerator->enumerate(enumerator, &block)) | |
312 | { | |
313 | if (first) | |
314 | { | |
315 | first = FALSE; | |
316 | } | |
317 | else | |
318 | { | |
319 | printf(", "); | |
320 | } | |
321 | printf("%R", block); | |
322 | } | |
323 | enumerator->destroy(enumerator); | |
324 | printf("\n"); | |
325 | } | |
326 | } | |
327 | ||
21f80e9d MW |
328 | /** |
329 | * Print CRL specific information | |
330 | */ | |
331 | static void print_crl(crl_t *crl) | |
332 | { | |
333 | enumerator_t *enumerator; | |
334 | time_t ts; | |
335 | crl_reason_t reason; | |
336 | chunk_t chunk; | |
337 | int count = 0; | |
de8521f6 | 338 | bool first; |
21f80e9d MW |
339 | char buf[64]; |
340 | struct tm tm; | |
de8521f6 | 341 | x509_cdp_t *cdp; |
21f80e9d | 342 | |
e464894e | 343 | chunk = chunk_skip_zero(crl->get_serial(crl)); |
21f80e9d | 344 | printf("serial: %#B\n", &chunk); |
e464894e | 345 | |
de8521f6 MW |
346 | if (crl->is_delta_crl(crl, &chunk)) |
347 | { | |
71c9565a | 348 | chunk = chunk_skip_zero(chunk); |
de8521f6 MW |
349 | printf("delta CRL: for serial %#B\n", &chunk); |
350 | } | |
21f80e9d MW |
351 | chunk = crl->get_authKeyIdentifier(crl); |
352 | printf("authKeyId: %#B\n", &chunk); | |
353 | ||
de8521f6 MW |
354 | first = TRUE; |
355 | enumerator = crl->create_delta_crl_uri_enumerator(crl); | |
356 | while (enumerator->enumerate(enumerator, &cdp)) | |
357 | { | |
358 | if (first) | |
359 | { | |
360 | printf("freshest: %s", cdp->uri); | |
361 | first = FALSE; | |
362 | } | |
363 | else | |
364 | { | |
365 | printf(" %s", cdp->uri); | |
366 | } | |
367 | if (cdp->issuer) | |
368 | { | |
369 | printf(" (CRL issuer: %Y)", cdp->issuer); | |
370 | } | |
371 | printf("\n"); | |
372 | } | |
373 | enumerator->destroy(enumerator); | |
374 | ||
21f80e9d MW |
375 | enumerator = crl->create_enumerator(crl); |
376 | while (enumerator->enumerate(enumerator, &chunk, &ts, &reason)) | |
377 | { | |
378 | count++; | |
379 | } | |
380 | enumerator->destroy(enumerator); | |
381 | ||
382 | printf("%d revoked certificate%s%s\n", count, | |
383 | count == 1 ? "" : "s", count ? ":" : ""); | |
384 | enumerator = crl->create_enumerator(crl); | |
385 | while (enumerator->enumerate(enumerator, &chunk, &ts, &reason)) | |
386 | { | |
e464894e | 387 | chunk = chunk_skip_zero(chunk); |
21f80e9d MW |
388 | localtime_r(&ts, &tm); |
389 | strftime(buf, sizeof(buf), "%F %T", &tm); | |
390 | printf(" %#B %N %s\n", &chunk, crl_reason_names, reason, buf); | |
391 | count++; | |
392 | } | |
393 | enumerator->destroy(enumerator); | |
394 | } | |
395 | ||
20ea84da MW |
396 | /** |
397 | * Print AC specific information | |
398 | */ | |
399 | static void print_ac(ac_t *ac) | |
400 | { | |
401 | ac_group_type_t type; | |
402 | identification_t *id; | |
403 | enumerator_t *groups; | |
404 | chunk_t chunk; | |
405 | bool first = TRUE; | |
406 | ||
407 | chunk = chunk_skip_zero(ac->get_serial(ac)); | |
408 | printf("serial: %#B\n", &chunk); | |
409 | ||
410 | id = ac->get_holderIssuer(ac); | |
411 | if (id) | |
412 | { | |
413 | printf("hissuer: \"%Y\"\n", id); | |
414 | } | |
415 | chunk = chunk_skip_zero(ac->get_holderSerial(ac)); | |
416 | if (chunk.ptr) | |
417 | { | |
418 | printf("hserial: %#B\n", &chunk); | |
419 | } | |
420 | groups = ac->create_group_enumerator(ac); | |
421 | while (groups->enumerate(groups, &type, &chunk)) | |
422 | { | |
423 | int oid; | |
424 | char *str; | |
425 | ||
426 | if (first) | |
427 | { | |
428 | printf("groups: "); | |
429 | first = FALSE; | |
430 | } | |
431 | else | |
432 | { | |
433 | printf(" "); | |
434 | } | |
435 | switch (type) | |
436 | { | |
437 | case AC_GROUP_TYPE_STRING: | |
438 | printf("%.*s", (int)chunk.len, chunk.ptr); | |
439 | break; | |
440 | case AC_GROUP_TYPE_OID: | |
441 | oid = asn1_known_oid(chunk); | |
442 | if (oid == OID_UNKNOWN) | |
443 | { | |
444 | str = asn1_oid_to_string(chunk); | |
445 | if (str) | |
446 | { | |
447 | printf("%s", str); | |
297bc06c | 448 | free(str); |
20ea84da MW |
449 | } |
450 | else | |
451 | { | |
452 | printf("OID:%#B", &chunk); | |
453 | } | |
454 | } | |
455 | else | |
456 | { | |
457 | printf("%s", oid_names[oid].name); | |
458 | } | |
459 | break; | |
460 | case AC_GROUP_TYPE_OCTETS: | |
461 | printf("%#B", &chunk); | |
462 | break; | |
463 | } | |
464 | printf("\n"); | |
465 | } | |
466 | groups->destroy(groups); | |
467 | ||
468 | chunk = ac->get_authKeyIdentifier(ac); | |
469 | if (chunk.ptr) | |
470 | { | |
471 | printf("authkey: %#B\n", &chunk); | |
472 | } | |
473 | } | |
474 | ||
2e57b212 MW |
475 | /** |
476 | * Print certificate information | |
477 | */ | |
478 | static void print_cert(certificate_t *cert) | |
479 | { | |
480 | time_t now, notAfter, notBefore; | |
481 | public_key_t *key; | |
482 | ||
483 | now = time(NULL); | |
484 | ||
485 | printf("cert: %N\n", certificate_type_names, cert->get_type(cert)); | |
21f80e9d MW |
486 | if (cert->get_type(cert) != CERT_X509_CRL) |
487 | { | |
488 | printf("subject: \"%Y\"\n", cert->get_subject(cert)); | |
489 | } | |
2e57b212 MW |
490 | printf("issuer: \"%Y\"\n", cert->get_issuer(cert)); |
491 | ||
492 | cert->get_validity(cert, &now, ¬Before, ¬After); | |
493 | printf("validity: not before %T, ", ¬Before, FALSE); | |
494 | if (now < notBefore) | |
495 | { | |
496 | printf("not valid yet (valid in %V)\n", &now, ¬Before); | |
497 | } | |
498 | else | |
499 | { | |
500 | printf("ok\n"); | |
501 | } | |
502 | printf(" not after %T, ", ¬After, FALSE); | |
503 | if (now > notAfter) | |
504 | { | |
505 | printf("expired (%V ago)\n", &now, ¬After); | |
506 | } | |
507 | else | |
508 | { | |
509 | printf("ok (expires in %V)\n", &now, ¬After); | |
510 | } | |
511 | ||
512 | switch (cert->get_type(cert)) | |
513 | { | |
514 | case CERT_X509: | |
515 | print_x509((x509_t*)cert); | |
516 | break; | |
21f80e9d MW |
517 | case CERT_X509_CRL: |
518 | print_crl((crl_t*)cert); | |
519 | break; | |
20ea84da MW |
520 | case CERT_X509_AC: |
521 | print_ac((ac_t*)cert); | |
522 | break; | |
2e57b212 MW |
523 | default: |
524 | printf("parsing certificate subtype %N not implemented\n", | |
525 | certificate_type_names, cert->get_type(cert)); | |
526 | break; | |
527 | } | |
2e57b212 MW |
528 | key = cert->get_public_key(cert); |
529 | if (key) | |
530 | { | |
531 | print_pubkey(key); | |
532 | key->destroy(key); | |
533 | } | |
2e57b212 MW |
534 | } |
535 | ||
536 | /** | |
537 | * Print a credential in a human readable form | |
538 | */ | |
539 | static int print() | |
540 | { | |
541 | credential_type_t type = CRED_CERTIFICATE; | |
542 | int subtype = CERT_X509; | |
543 | void *cred; | |
544 | char *arg, *file = NULL; | |
545 | ||
546 | while (TRUE) | |
547 | { | |
548 | switch (command_getopt(&arg)) | |
549 | { | |
550 | case 'h': | |
551 | return command_usage(NULL); | |
552 | case 't': | |
553 | if (streq(arg, "x509")) | |
554 | { | |
555 | type = CRED_CERTIFICATE; | |
556 | subtype = CERT_X509; | |
557 | } | |
21f80e9d MW |
558 | else if (streq(arg, "crl")) |
559 | { | |
560 | type = CRED_CERTIFICATE; | |
561 | subtype = CERT_X509_CRL; | |
562 | } | |
20ea84da MW |
563 | else if (streq(arg, "ac")) |
564 | { | |
565 | type = CRED_CERTIFICATE; | |
566 | subtype = CERT_X509_AC; | |
567 | } | |
2e57b212 MW |
568 | else if (streq(arg, "pub")) |
569 | { | |
570 | type = CRED_PUBLIC_KEY; | |
571 | subtype = KEY_ANY; | |
572 | } | |
573 | else if (streq(arg, "rsa-priv")) | |
574 | { | |
575 | type = CRED_PRIVATE_KEY; | |
576 | subtype = KEY_RSA; | |
577 | } | |
578 | else if (streq(arg, "ecdsa-priv")) | |
579 | { | |
580 | type = CRED_PRIVATE_KEY; | |
581 | subtype = KEY_ECDSA; | |
582 | } | |
583 | else | |
584 | { | |
585 | return command_usage( "invalid input type"); | |
586 | } | |
587 | continue; | |
588 | case 'i': | |
589 | file = arg; | |
590 | continue; | |
591 | case EOF: | |
592 | break; | |
593 | default: | |
594 | return command_usage("invalid --print option"); | |
595 | } | |
596 | break; | |
597 | } | |
598 | if (file) | |
599 | { | |
600 | cred = lib->creds->create(lib->creds, type, subtype, | |
601 | BUILD_FROM_FILE, file, BUILD_END); | |
602 | } | |
603 | else | |
604 | { | |
71c9565a TB |
605 | chunk_t chunk; |
606 | ||
13298719 | 607 | set_file_mode(stdin, CERT_ASN1_DER); |
1c4a3459 MW |
608 | if (!chunk_from_fd(0, &chunk)) |
609 | { | |
610 | fprintf(stderr, "reading input failed: %s\n", strerror(errno)); | |
611 | return 1; | |
612 | } | |
2e57b212 | 613 | cred = lib->creds->create(lib->creds, type, subtype, |
71c9565a TB |
614 | BUILD_BLOB, chunk, BUILD_END); |
615 | free(chunk.ptr); | |
2e57b212 MW |
616 | } |
617 | if (!cred) | |
618 | { | |
619 | fprintf(stderr, "parsing input failed\n"); | |
620 | return 1; | |
621 | } | |
622 | ||
623 | if (type == CRED_CERTIFICATE) | |
624 | { | |
625 | certificate_t *cert = (certificate_t*)cred; | |
626 | ||
627 | print_cert(cert); | |
628 | cert->destroy(cert); | |
629 | } | |
630 | if (type == CRED_PUBLIC_KEY) | |
631 | { | |
632 | public_key_t *key = (public_key_t*)cred; | |
633 | ||
634 | print_pubkey(key); | |
635 | key->destroy(key); | |
636 | } | |
637 | if (type == CRED_PRIVATE_KEY) | |
638 | { | |
639 | private_key_t *key = (private_key_t*)cred; | |
640 | ||
641 | print_key(key); | |
642 | key->destroy(key); | |
643 | } | |
644 | return 0; | |
645 | } | |
646 | ||
647 | /** | |
648 | * Register the command. | |
649 | */ | |
650 | static void __attribute__ ((constructor))reg() | |
651 | { | |
652 | command_register((command_t) | |
653 | { print, 'a', "print", | |
654 | "print a credential in a human readable form", | |
20ea84da | 655 | {"[--in file] [--type rsa-priv|ecdsa-priv|pub|x509|crl|ac]"}, |
2e57b212 MW |
656 | { |
657 | {"help", 'h', 0, "show usage information"}, | |
658 | {"in", 'i', 1, "input file, default: stdin"}, | |
659 | {"type", 't', 1, "type of credential, default: x509"}, | |
660 | } | |
661 | }); | |
662 | } |