1 /* $OpenBSD: ciphers.c,v 1.4 2015/03/02 07:51:25 bcook 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 struct { 27 int ssl_version; 28 int usage; 29 int verbose; 30 } ciphers_config; 31 32 struct option ciphers_options[] = { 33 { 34 .name = "h", 35 .type = OPTION_FLAG, 36 .opt.flag = &ciphers_config.usage, 37 }, 38 { 39 .name = "?", 40 .type = OPTION_FLAG, 41 .opt.flag = &ciphers_config.usage, 42 }, 43 { 44 .name = "ssl3", 45 .desc = "Only include SSLv3 ciphers", 46 .type = OPTION_VALUE, 47 .opt.value = &ciphers_config.ssl_version, 48 .value = SSL3_VERSION, 49 }, 50 { 51 .name = "tls1", 52 .desc = "Only include TLSv1 ciphers", 53 .type = OPTION_VALUE, 54 .opt.value = &ciphers_config.ssl_version, 55 .value = TLS1_VERSION, 56 }, 57 { 58 .name = "v", 59 .desc = "Provide cipher listing", 60 .type = OPTION_VALUE, 61 .opt.value = &ciphers_config.verbose, 62 .value = 1, 63 }, 64 { 65 .name = "V", 66 .desc = "Provide cipher listing with cipher suite values", 67 .type = OPTION_VALUE, 68 .opt.value = &ciphers_config.verbose, 69 .value = 2, 70 }, 71 { NULL }, 72 }; 73 74 static void 75 ciphers_usage(void) 76 { 77 fprintf(stderr, "usage: ciphers [-hVv] [-ssl3 | -tls1] [cipherlist]\n"); 78 options_usage(ciphers_options); 79 } 80 81 int 82 ciphers_main(int argc, char **argv) 83 { 84 char *cipherlist = NULL; 85 STACK_OF(SSL_CIPHER) *ciphers; 86 const SSL_METHOD *ssl_method; 87 const SSL_CIPHER *cipher; 88 SSL_CTX *ssl_ctx = NULL; 89 SSL *ssl = NULL; 90 uint16_t value; 91 int i, rv = 0; 92 char *desc; 93 94 memset(&ciphers_config, 0, sizeof(ciphers_config)); 95 96 if (options_parse(argc, argv, ciphers_options, &cipherlist, 97 NULL) != 0) { 98 ciphers_usage(); 99 return (1); 100 } 101 102 if (ciphers_config.usage) { 103 ciphers_usage(); 104 return (1); 105 } 106 107 switch (ciphers_config.ssl_version) { 108 case SSL3_VERSION: 109 ssl_method = SSLv3_client_method(); 110 break; 111 case TLS1_VERSION: 112 ssl_method = TLSv1_client_method(); 113 break; 114 default: 115 ssl_method = SSLv3_server_method(); 116 } 117 118 if ((ssl_ctx = SSL_CTX_new(ssl_method)) == NULL) 119 goto err; 120 121 if (cipherlist != NULL) { 122 if (SSL_CTX_set_cipher_list(ssl_ctx, cipherlist) == 0) 123 goto err; 124 } 125 126 if ((ssl = SSL_new(ssl_ctx)) == NULL) 127 goto err; 128 129 if ((ciphers = SSL_get_ciphers(ssl)) == NULL) 130 goto err; 131 132 for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { 133 cipher = sk_SSL_CIPHER_value(ciphers, i); 134 if (ciphers_config.verbose == 0) { 135 fprintf(stdout, "%s%s", (i ? ":" : ""), 136 SSL_CIPHER_get_name(cipher)); 137 continue; 138 } 139 if (ciphers_config.verbose > 1) { 140 value = SSL_CIPHER_get_value(cipher); 141 fprintf(stdout, "%-*s0x%02X,0x%02X - ", 10, "", 142 ((value >> 8) & 0xff), (value & 0xff)); 143 } 144 desc = SSL_CIPHER_description(cipher, NULL, 0); 145 if (strcmp(desc, "OPENSSL_malloc Error") == 0) { 146 fprintf(stderr, "out of memory\n"); 147 goto err; 148 } 149 fprintf(stdout, "%s", desc); 150 free(desc); 151 } 152 if (ciphers_config.verbose == 0) 153 fprintf(stdout, "\n"); 154 155 goto done; 156 157 err: 158 ERR_print_errors_fp(stderr); 159 rv = 1; 160 161 done: 162 SSL_CTX_free(ssl_ctx); 163 SSL_free(ssl); 164 165 return (rv); 166 } 167