1 /* $OpenBSD: ciphers.c,v 1.15 2022/07/19 20:15:19 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 struct { 28 int usage; 29 int use_supported; 30 int verbose; 31 int version; 32 } ciphers_config; 33 34 static const struct option ciphers_options[] = { 35 { 36 .name = "h", 37 .type = OPTION_FLAG, 38 .opt.flag = &ciphers_config.usage, 39 }, 40 { 41 .name = "?", 42 .type = OPTION_FLAG, 43 .opt.flag = &ciphers_config.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 = &ciphers_config.use_supported, 50 }, 51 { 52 .name = "tls1", 53 .desc = "Use TLS protocol version 1", 54 .type = OPTION_VALUE, 55 .opt.value = &ciphers_config.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 = &ciphers_config.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 = &ciphers_config.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 = &ciphers_config.version, 77 .value = TLS1_3_VERSION, 78 }, 79 { 80 .name = "v", 81 .desc = "Provide cipher listing", 82 .type = OPTION_VALUE, 83 .opt.value = &ciphers_config.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 = &ciphers_config.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 (single_execution) { 118 if (pledge("stdio rpath", NULL) == -1) { 119 perror("pledge"); 120 exit(1); 121 } 122 } 123 124 memset(&ciphers_config, 0, sizeof(ciphers_config)); 125 126 if (options_parse(argc, argv, ciphers_options, &cipherlist, 127 NULL) != 0) { 128 ciphers_usage(); 129 return (1); 130 } 131 132 if (ciphers_config.usage) { 133 ciphers_usage(); 134 return (1); 135 } 136 137 if ((ssl_ctx = SSL_CTX_new(TLS_method())) == NULL) 138 goto err; 139 140 if (ciphers_config.version != 0) { 141 if (!SSL_CTX_set_min_proto_version(ssl_ctx, 142 ciphers_config.version)) 143 goto err; 144 if (!SSL_CTX_set_max_proto_version(ssl_ctx, 145 ciphers_config.version)) 146 goto err; 147 } 148 149 if (cipherlist != NULL) { 150 if (SSL_CTX_set_cipher_list(ssl_ctx, cipherlist) == 0) 151 goto err; 152 } 153 154 if ((ssl = SSL_new(ssl_ctx)) == NULL) 155 goto err; 156 157 if (ciphers_config.use_supported) { 158 if ((supported_ciphers = 159 SSL_get1_supported_ciphers(ssl)) == NULL) 160 goto err; 161 ciphers = supported_ciphers; 162 } else { 163 if ((ciphers = SSL_get_ciphers(ssl)) == NULL) 164 goto err; 165 } 166 167 for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { 168 cipher = sk_SSL_CIPHER_value(ciphers, i); 169 if (ciphers_config.verbose == 0) { 170 fprintf(stdout, "%s%s", (i ? ":" : ""), 171 SSL_CIPHER_get_name(cipher)); 172 continue; 173 } 174 if (ciphers_config.verbose > 1) { 175 value = SSL_CIPHER_get_value(cipher); 176 fprintf(stdout, "%-*s0x%02X,0x%02X - ", 10, "", 177 ((value >> 8) & 0xff), (value & 0xff)); 178 } 179 desc = SSL_CIPHER_description(cipher, NULL, 0); 180 if (strcmp(desc, "OPENSSL_malloc Error") == 0) { 181 fprintf(stderr, "out of memory\n"); 182 goto err; 183 } 184 fprintf(stdout, "%s", desc); 185 free(desc); 186 } 187 if (ciphers_config.verbose == 0) 188 fprintf(stdout, "\n"); 189 190 goto done; 191 192 err: 193 ERR_print_errors_fp(stderr); 194 rv = 1; 195 196 done: 197 sk_SSL_CIPHER_free(supported_ciphers); 198 SSL_CTX_free(ssl_ctx); 199 SSL_free(ssl); 200 201 return (rv); 202 } 203