1 /* $OpenBSD: ciphers.c,v 1.20 2025/01/02 12:31:44 tb Exp $ */
2 /*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20
21 #include <openssl/err.h>
22 #include <openssl/ssl.h>
23
24 #include "apps.h"
25
26 static struct {
27 int usage;
28 int use_supported;
29 int verbose;
30 int version;
31 } cfg;
32
33 static const struct option ciphers_options[] = {
34 {
35 .name = "h",
36 .type = OPTION_FLAG,
37 .opt.flag = &cfg.usage,
38 },
39 {
40 .name = "?",
41 .type = OPTION_FLAG,
42 .opt.flag = &cfg.usage,
43 },
44 {
45 .name = "s",
46 .desc = "Only list ciphers that are supported by the TLS method",
47 .type = OPTION_FLAG,
48 .opt.flag = &cfg.use_supported,
49 },
50 {
51 .name = "tls1_2",
52 .desc = "Use TLS protocol version 1.2",
53 .type = OPTION_VALUE,
54 .opt.value = &cfg.version,
55 .value = TLS1_2_VERSION,
56 },
57 {
58 .name = "tls1_3",
59 .desc = "Use TLS protocol version 1.3",
60 .type = OPTION_VALUE,
61 .opt.value = &cfg.version,
62 .value = TLS1_3_VERSION,
63 },
64 {
65 .name = "v",
66 .desc = "Provide cipher listing",
67 .type = OPTION_VALUE,
68 .opt.value = &cfg.verbose,
69 .value = 1,
70 },
71 {
72 .name = "V",
73 .desc = "Provide cipher listing with cipher suite values",
74 .type = OPTION_VALUE,
75 .opt.value = &cfg.verbose,
76 .value = 2,
77 },
78 { NULL },
79 };
80
81 static void
ciphers_usage(void)82 ciphers_usage(void)
83 {
84 fprintf(stderr, "usage: ciphers [-hsVv] [-tls1_2] "
85 "[-tls1_3] [cipherlist]\n");
86 options_usage(ciphers_options);
87 }
88
89 int
ciphers_main(int argc,char ** argv)90 ciphers_main(int argc, char **argv)
91 {
92 char *cipherlist = NULL;
93 STACK_OF(SSL_CIPHER) *ciphers;
94 STACK_OF(SSL_CIPHER) *supported_ciphers = NULL;
95 const SSL_CIPHER *cipher;
96 SSL_CTX *ssl_ctx = NULL;
97 SSL *ssl = NULL;
98 uint16_t value;
99 int i, rv = 0;
100 char *desc;
101
102 if (pledge("stdio rpath", NULL) == -1) {
103 perror("pledge");
104 exit(1);
105 }
106
107 memset(&cfg, 0, sizeof(cfg));
108
109 if (options_parse(argc, argv, ciphers_options, &cipherlist,
110 NULL) != 0) {
111 ciphers_usage();
112 return (1);
113 }
114
115 if (cfg.usage) {
116 ciphers_usage();
117 return (1);
118 }
119
120 if ((ssl_ctx = SSL_CTX_new(TLS_method())) == NULL)
121 goto err;
122
123 if (cfg.version != 0) {
124 if (!SSL_CTX_set_min_proto_version(ssl_ctx,
125 cfg.version))
126 goto err;
127 if (!SSL_CTX_set_max_proto_version(ssl_ctx,
128 cfg.version))
129 goto err;
130 }
131
132 if (cipherlist != NULL) {
133 if (SSL_CTX_set_cipher_list(ssl_ctx, cipherlist) == 0)
134 goto err;
135 }
136
137 if ((ssl = SSL_new(ssl_ctx)) == NULL)
138 goto err;
139
140 if (cfg.use_supported) {
141 if ((supported_ciphers =
142 SSL_get1_supported_ciphers(ssl)) == NULL)
143 goto err;
144 ciphers = supported_ciphers;
145 } else {
146 if ((ciphers = SSL_get_ciphers(ssl)) == NULL)
147 goto err;
148 }
149
150 for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
151 cipher = sk_SSL_CIPHER_value(ciphers, i);
152 if (cfg.verbose == 0) {
153 fprintf(stdout, "%s%s", (i ? ":" : ""),
154 SSL_CIPHER_get_name(cipher));
155 continue;
156 }
157 if (cfg.verbose > 1) {
158 value = SSL_CIPHER_get_value(cipher);
159 fprintf(stdout, "%-*s0x%02X,0x%02X - ", 10, "",
160 ((value >> 8) & 0xff), (value & 0xff));
161 }
162 desc = SSL_CIPHER_description(cipher, NULL, 0);
163 if (strcmp(desc, "OPENSSL_malloc Error") == 0) {
164 fprintf(stderr, "out of memory\n");
165 goto err;
166 }
167 fprintf(stdout, "%s", desc);
168 free(desc);
169 }
170 if (cfg.verbose == 0)
171 fprintf(stdout, "\n");
172
173 goto done;
174
175 err:
176 ERR_print_errors_fp(stderr);
177 rv = 1;
178
179 done:
180 sk_SSL_CIPHER_free(supported_ciphers);
181 SSL_CTX_free(ssl_ctx);
182 SSL_free(ssl);
183
184 return (rv);
185 }
186