1 /* $OpenBSD: ciphers.c,v 1.18 2023/03/06 14:32:05 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 #include "progs.h" 26 27 static struct { 28 int usage; 29 int use_supported; 30 int verbose; 31 int version; 32 } cfg; 33 34 static const struct option ciphers_options[] = { 35 { 36 .name = "h", 37 .type = OPTION_FLAG, 38 .opt.flag = &cfg.usage, 39 }, 40 { 41 .name = "?", 42 .type = OPTION_FLAG, 43 .opt.flag = &cfg.usage, 44 }, 45 { 46 .name = "s", 47 .desc = "Only list ciphers that are supported by the TLS method", 48 .type = OPTION_FLAG, 49 .opt.flag = &cfg.use_supported, 50 }, 51 { 52 .name = "tls1", 53 .desc = "Use TLS protocol version 1", 54 .type = OPTION_VALUE, 55 .opt.value = &cfg.version, 56 .value = TLS1_VERSION, 57 }, 58 { 59 .name = "tls1_1", 60 .desc = "Use TLS protocol version 1.1", 61 .type = OPTION_VALUE, 62 .opt.value = &cfg.version, 63 .value = TLS1_1_VERSION, 64 }, 65 { 66 .name = "tls1_2", 67 .desc = "Use TLS protocol version 1.2", 68 .type = OPTION_VALUE, 69 .opt.value = &cfg.version, 70 .value = TLS1_2_VERSION, 71 }, 72 { 73 .name = "tls1_3", 74 .desc = "Use TLS protocol version 1.3", 75 .type = OPTION_VALUE, 76 .opt.value = &cfg.version, 77 .value = TLS1_3_VERSION, 78 }, 79 { 80 .name = "v", 81 .desc = "Provide cipher listing", 82 .type = OPTION_VALUE, 83 .opt.value = &cfg.verbose, 84 .value = 1, 85 }, 86 { 87 .name = "V", 88 .desc = "Provide cipher listing with cipher suite values", 89 .type = OPTION_VALUE, 90 .opt.value = &cfg.verbose, 91 .value = 2, 92 }, 93 { NULL }, 94 }; 95 96 static void 97 ciphers_usage(void) 98 { 99 fprintf(stderr, "usage: ciphers [-hsVv] [-tls1] [-tls1_1] [-tls1_2] " 100 "[-tls1_3] [cipherlist]\n"); 101 options_usage(ciphers_options); 102 } 103 104 int 105 ciphers_main(int argc, char **argv) 106 { 107 char *cipherlist = NULL; 108 STACK_OF(SSL_CIPHER) *ciphers; 109 STACK_OF(SSL_CIPHER) *supported_ciphers = NULL; 110 const SSL_CIPHER *cipher; 111 SSL_CTX *ssl_ctx = NULL; 112 SSL *ssl = NULL; 113 uint16_t value; 114 int i, rv = 0; 115 char *desc; 116 117 if (pledge("stdio rpath", NULL) == -1) { 118 perror("pledge"); 119 exit(1); 120 } 121 122 memset(&cfg, 0, sizeof(cfg)); 123 124 if (options_parse(argc, argv, ciphers_options, &cipherlist, 125 NULL) != 0) { 126 ciphers_usage(); 127 return (1); 128 } 129 130 if (cfg.usage) { 131 ciphers_usage(); 132 return (1); 133 } 134 135 if ((ssl_ctx = SSL_CTX_new(TLS_method())) == NULL) 136 goto err; 137 138 if (cfg.version != 0) { 139 if (!SSL_CTX_set_min_proto_version(ssl_ctx, 140 cfg.version)) 141 goto err; 142 if (!SSL_CTX_set_max_proto_version(ssl_ctx, 143 cfg.version)) 144 goto err; 145 } 146 147 if (cipherlist != NULL) { 148 if (SSL_CTX_set_cipher_list(ssl_ctx, cipherlist) == 0) 149 goto err; 150 } 151 152 if ((ssl = SSL_new(ssl_ctx)) == NULL) 153 goto err; 154 155 if (cfg.use_supported) { 156 if ((supported_ciphers = 157 SSL_get1_supported_ciphers(ssl)) == NULL) 158 goto err; 159 ciphers = supported_ciphers; 160 } else { 161 if ((ciphers = SSL_get_ciphers(ssl)) == NULL) 162 goto err; 163 } 164 165 for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { 166 cipher = sk_SSL_CIPHER_value(ciphers, i); 167 if (cfg.verbose == 0) { 168 fprintf(stdout, "%s%s", (i ? ":" : ""), 169 SSL_CIPHER_get_name(cipher)); 170 continue; 171 } 172 if (cfg.verbose > 1) { 173 value = SSL_CIPHER_get_value(cipher); 174 fprintf(stdout, "%-*s0x%02X,0x%02X - ", 10, "", 175 ((value >> 8) & 0xff), (value & 0xff)); 176 } 177 desc = SSL_CIPHER_description(cipher, NULL, 0); 178 if (strcmp(desc, "OPENSSL_malloc Error") == 0) { 179 fprintf(stderr, "out of memory\n"); 180 goto err; 181 } 182 fprintf(stdout, "%s", desc); 183 free(desc); 184 } 185 if (cfg.verbose == 0) 186 fprintf(stdout, "\n"); 187 188 goto done; 189 190 err: 191 ERR_print_errors_fp(stderr); 192 rv = 1; 193 194 done: 195 sk_SSL_CIPHER_free(supported_ciphers); 196 SSL_CTX_free(ssl_ctx); 197 SSL_free(ssl); 198 199 return (rv); 200 } 201