Skip to content

Commit

Permalink
ALPN protocol id enumeration
Browse files Browse the repository at this point in the history
  • Loading branch information
Ubuntu committed Sep 25, 2023
1 parent 03d3c16 commit fcad03c
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 2 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
tls-scan -- History of changes.
Bug numbers referenced in this log correspond to bug numbers at our issue tracker,

Version 1.6.0 (2023-09-25)
+-----------------------------------
* New feature: ALPN protocol id enumeration. A new field `alpn`
is added to the JSON output to indicate ALPN protocol id
selected by the server. Besides alpn, `sni` is also added
as a new field to indicate SNI value set by the client.

Version 1.5.2 (2023-09-24)
+-----------------------------------
* Build bug fix: https://github.com/prbinu/tls-scan/issues/59
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ A program to scan TLS based servers and collect X.509 certificates, ciphers and
* TLS and StartTLS protocol support: SMTP, IMAP, POP3, FTPS, SIEVE, NNTP, XMPP, LDAP, RDP, POSTGRES, MYSQL
* Blazing fast - Can operate at scale with the ability to concurrently scan large number of servers (say scan IoT devices at scale)
* Detect SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3 versions and ciphers
* ALPN protocol id enumeration
* Cipher and TLS version enumeration
* Extract X.509 certificate fields from the target server and print it in JSON format
* Certificate and host name verification checks
Expand Down
24 changes: 24 additions & 0 deletions cert-parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,21 @@ void ts_tls_cert_parse(SSL *ssl, struct tls_cert *tls_cert,
EVP_PKEY_free(key);
}

tls_cert->sni[0] = 0;
const char *sni = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (sni != NULL) {
strcpy(tls_cert->sni, sni);
}

const unsigned char *data = NULL;
unsigned int len = 0;
SSL_get0_alpn_selected(ssl, &data, &len);
tls_cert->alpn[0] = 0;
if (len > 0) {
strncpy(tls_cert->alpn, (char*)data, len);
tls_cert->alpn[len] = 0;
}

tls_cert->secure_renego =
SSL_get_secure_renegotiation_support(ssl) ? true : false;

Expand Down Expand Up @@ -660,6 +675,15 @@ void ts_tls_print_json(struct tls_cert *tls_cert, FILE *fp, bool pretty)

fprintf(fp, "%.*s\"port\": %d,%c", FMT_INDENT(2), tls_cert->port, fmt);
fprintf(fp, "%.*s\"elapsedTime\": %d,%c", FMT_INDENT(2), tls_cert->elapsed_time_ms, fmt);

if (tls_cert->sni[0] != 0) {
fprintf(fp, "%.*s\"sni\": \"%s\",%c", FMT_INDENT(2), tls_cert->sni, fmt);
}

if (tls_cert->alpn[0] != 0) {
fprintf(fp, "%.*s\"alpn\": \"%s\",%c", FMT_INDENT(2), tls_cert->alpn, fmt);
}

fprintf(fp, "%.*s\"tlsVersion\": \"%s\",%c", FMT_INDENT(2),
tls_cert->tls_version, fmt);
fprintf(fp, "%.*s\"cipher\": \"%s\",%c", FMT_INDENT(2), tls_cert->cipher, fmt);
Expand Down
2 changes: 2 additions & 0 deletions include/cert-parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ struct tls_cert {
char ip[OPT_STRLEN];
uint16_t port;
char cipher[128];
char sni[256];
char alpn[256];
char tls_version[8];
bool secure_renego;
char compression[32];
Expand Down
3 changes: 3 additions & 0 deletions include/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <gnutls/gnutls.h>

#define DEFAULT_HOSTLEN 256
#define DEFAULT_ALPNLEN 2048
#define OPT_STRLEN 256
#define OPT_CIPHER_STRLEN 4092
#define OPT_CIPHERSUITES_STRLEN 512
Expand Down Expand Up @@ -89,6 +90,8 @@ typedef struct options {
bool tls1_2;
bool tls1_3;
char cacert[OPT_STRLEN];
unsigned char alpn[DEFAULT_ALPNLEN];
size_t alpn_size;
char sni[DEFAULT_HOSTLEN];
char ciphers[OPT_CIPHER_STRLEN];
bool cipher_user_input; // user provided cipher flag
Expand Down
37 changes: 35 additions & 2 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,24 @@ void global_init()
/* returns current scan type/state */
scan_type_t ts_scan_type(const client_t *cli);

size_t alpn_wireformat(const char* alpn_str, unsigned char alpn[])
{
char *c = NULL;
char *c2 = strdup(alpn_str);
char *tptr = c2;
int index = 0;
size_t len = 0;
while ((c = strtok_r(tptr, ", ", &tptr))) {
len = strlen(c);
alpn[index++] = (unsigned char)len;
memcpy(&alpn[index], c, len);
index = index + len;
}

alpn[index+1] = 0;
free(c2);
return index;
}
// https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_ciphersuites.html
// seperate given ciphers into to TLS1.3 and pre-TLS1.3 cipher group
void get_ciphersuites_and_cipher_list(const char *ciphers,
Expand Down Expand Up @@ -289,6 +307,11 @@ SSL *ts_ssl_create(SSL_CTX *ssl_ctx, client_t *cli)
} else if (cli->host[0] != 0) {
SSL_set_tlsext_host_name(ssl, cli->host);
}

// Set ALPN protocol ids
if (cli->op->alpn_size != 0) {
SSL_set_alpn_protos(ssl, cli->op->alpn, cli->op->alpn_size);
}
}

return ssl;
Expand Down Expand Up @@ -1375,6 +1398,8 @@ void print_usage()
printf(" %s\n", "-T --session-file=<file>");
printf(" %s\n", " Pass file that contains SSL session in PEM format");
printf(" %s\n", "-a --all Enable --version-enum and --cipher-enum");
printf(" %s\n", "-A --alpn=<proto-list> Comma separated ALPN protocol id list passed in ClientHello");
printf(" %s\n", " Example: -A \"spdy/3,h2,http/1.1\"");
printf(" %s\n", "-s --sni=<host> Set TLS extension servername in ClientHello");
printf(" %s\n", " Defaults to input hostname & Applied to TLSv1+ only");
printf(" %s\n", "-b --concurrency=<number>");
Expand Down Expand Up @@ -1452,6 +1477,7 @@ int main(int argc, char **argv)
{"session-print", no_argument, 0, 'u'},
{"session-file", required_argument, 0, 'T'},
{"all", no_argument, 0, 'a'},
{"alpn", required_argument, 0, 'A'},
{"sni", required_argument, 0, 's'},
{"ssl2", no_argument, 0, '2'},
{"ssl3", no_argument, 0, '3'},
Expand Down Expand Up @@ -1509,12 +1535,12 @@ int main(int argc, char **argv)
op.tls1_1 = false;
op.tls1_2 = false;
op.protocol_adapter_index = -1;

char alpn[DEFAULT_ALPNLEN];
int tmsec = 0;
int tsec = 0;
while ((opt = getopt_long(argc,
argv,
"P:h:p:c:C:eUruT:as:b:vt:S:o:N:R:123456Q789VXnOjMH",
"P:h:p:c:C:eUruT:aA:s:b:vt:S:o:N:R:123456Q789VXnOjMH",
long_options, &long_index)) != -1) {
valid = 1;
switch (opt) {
Expand Down Expand Up @@ -1563,6 +1589,9 @@ int main(int argc, char **argv)
op.tls_vers_enum = true;
//op.session_reuse_test = true;
break;
case 'A':
snprintf(alpn, DEFAULT_ALPNLEN, "%s", optarg);
break;
case 's':
snprintf(op.sni, DEFAULT_HOSTLEN, "%s", optarg);
break;
Expand Down Expand Up @@ -1714,6 +1743,10 @@ int main(int argc, char **argv)
assert(in_handle.fp != NULL);
}

if (strlen(alpn) > 0) {
op.alpn_size = alpn_wireformat(alpn, &op.alpn[0]);
}

signal(SIGPIPE, SIG_IGN);

init_stats(&stats);
Expand Down

0 comments on commit fcad03c

Please sign in to comment.