Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ sniproxy_SOURCES = sniproxy.c \
table.c \
table.h \
tls.c \
tls.h
tls.h \
dtls.c \
dtls.h \
sni.c \
sni.h

sniproxy_LDADD = $(LIBEV_LIBS) $(LIBPCRE_LIBS) $(LIBUDNS_LIBS)
176 changes: 176 additions & 0 deletions src/dtls.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
* Copyright (c) 2020 Cisco and/or its affiliates.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This is a minimal DTLS implementation intended only to parse the server name
* extension. This was created based primarily on Wireshark dissection of a
* DTLS handshake and RFC4366.
*/

#include <stdio.h>
#include <stdlib.h> /* malloc() */
#include <stdint.h>
#include <string.h> /* strncpy() */
#include <sys/socket.h>
#include <sys/types.h>
#include "dtls.h"
#include "sni.h"
#include "protocol.h"
#include "logger.h"

#define DTLS_HANDSHAKE_CONTENT_TYPE 0x16
#define DTLS_VERSION_12 0xfefd
#define DTLS_HEADER_LEN 3
#define DTLS_HANDSHAKE_TYPE_CLIENT_HELLO 0x01

#ifndef MIN
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#endif

static int parse_dtls_header(const uint8_t*, size_t, char **);

static const char dtls_alert[] = {
0x15, /* DTLS Alert */
0x02, 0x01, /* DTLS version */
0x00, 0x02, /* Payload length */
0x02, 0x28, /* Fatal, handshake failure */
};

const struct Protocol *const dtls_protocol = &(struct Protocol){
.name = "dtls",
.default_port = 443,
.parse_packet = (int (*const)(const char *, size_t, char **))&parse_dtls_header,
.abort_message = dtls_alert,
.abort_message_len = sizeof(dtls_alert)
};


/* Parse a DTLS packet for the Server Name Indication extension in the client
* hello handshake, returning the first servername found (pointer to static
* array)
*
* Returns:
* >=0 - length of the hostname and updates *hostname
* caller is responsible for freeing *hostname
* -1 - Incomplete request
* -2 - No Host header included in this request
* -3 - Invalid hostname pointer
* -4 - malloc failure
* < -4 - Invalid TLS client hello
*/
static int
parse_dtls_header(const uint8_t *data, size_t data_len, char **hostname) {
uint8_t dtls_content_type;
uint16_t dtls_version;
size_t pos = DTLS_HEADER_LEN;
size_t len;

if (hostname == NULL)
return -3;

/* Check that our UDP payload is at least large enough for a DTLS header */
if (data_len < DTLS_HEADER_LEN)
return -1;


dtls_content_type = data[0];
if (dtls_content_type != DTLS_HANDSHAKE_CONTENT_TYPE) {
debug("Request did not begin with DTLS handshake.");
return -5;
}

dtls_version = data[1];
if (dtls_version != DTLS_VERSION_12) {
debug("Requested version of DTLS not supported.");
return -5;
}

/*
* Skip epoch (2 bytes) and sequence number (6 bytes).
* We want the length of this packet.
*/
len = ((size_t)data[9] << 8) +
(size_t)data[10] + DTLS_HEADER_LEN;
data_len = MIN(data_len, len);

/* Check we received entire DTLS record length */
if (data_len < len)
return -1;

/*
* Handshake
*/
if (pos + 1 > data_len) {
return -5;
}
if (data[pos] != DTLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
debug("Not a client hello");
return -5;
}

/*
* Skip past the following records:
*
* Length 3
* Message sequence 2
* Fragment offset 3
* Fragment length 3
* Version 2
* Random 32
*/
pos += 45;

/* Session ID */
if (pos + 1 > data_len)
return -5;
len = (size_t)data[pos];
pos += 1 + len;

/* Cookie length */
pos += 1;

/* Cipher Suites */
if (pos + 2 > data_len)
return -5;
len = ((size_t)data[pos] << 8) + (size_t)data[pos + 1];
pos += 2 + len;

/* Compression Methods */
if (pos + 1 > data_len)
return -5;
len = (size_t)data[pos];
pos += 1 + len;

/* Extensions */
if (pos + 2 > data_len)
return -5;
len = ((size_t)data[pos] << 8) + (size_t)data[pos + 1];
pos += 2;

if (pos + len > data_len)
return -5;
return parse_extensions(data + pos, len, hostname);
}
34 changes: 34 additions & 0 deletions src/dtls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2020 Cisco and/or its affiliates.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DTLS_H
#define DTLS_H

#include "protocol.h"

extern const struct Protocol *const dls_protocol;

#endif
105 changes: 105 additions & 0 deletions src/sni.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright (c) 2020 Cisco and/or its affiliates.
* Copyright (c) 2011 and 2012, Dustin Lundquist <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Minimal SNI extension processing, shared by TLS and DTLS.
*/
#include <stdio.h>
#include <stdlib.h> /* malloc() */
#include <stdint.h>
#include <string.h> /* strncpy() */
#include <sys/socket.h>
#include <sys/types.h>
#include "sni.h"
#include "protocol.h"
#include "logger.h"

int
parse_extensions(const uint8_t *data, size_t data_len, char **hostname) {
size_t pos = 0;
size_t len;

/* Parse each 4 bytes for the extension header */
while (pos + 4 <= data_len) {
/* Extension Length */
len = ((size_t)data[pos + 2] << 8) +
(size_t)data[pos + 3];

/* Check if it's a server name extension */
if (data[pos] == 0x00 && data[pos + 1] == 0x00) {
/* There can be only one extension of each type, so we break
our state and move p to beinnging of the extension here */
if (pos + 4 + len > data_len)
return -5;
return parse_server_name_extension(data + pos + 4, len, hostname);
}
pos += 4 + len; /* Advance to the next extension header */
}
/* Check we ended where we expected to */
if (pos != data_len)
return -5;

return -2;
}

int
parse_server_name_extension(const uint8_t *data, size_t data_len,
char **hostname) {
size_t pos = 2; /* skip server name list length */
size_t len;

while (pos + 3 < data_len) {
len = ((size_t)data[pos + 1] << 8) +
(size_t)data[pos + 2];

if (pos + 3 + len > data_len)
return -5;

switch (data[pos]) { /* name type */
case 0x00: /* host_name */
*hostname = malloc(len + 1);
if (*hostname == NULL) {
err("malloc() failure");
return -4;
}

strncpy(*hostname, (const char *)(data + pos + 3), len);

(*hostname)[len] = '\0';

return len;
default:
debug("Unknown server name extension name type: %" PRIu8,
data[pos]);
}
pos += 3 + len;
}
/* Check we ended where we expected to */
if (pos != data_len)
return -5;

return -2;
}
33 changes: 33 additions & 0 deletions src/sni.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2020 Cisco and/or its affiliates.
* Copyright (c) 2011 and 2012, Dustin Lundquist <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SNI_H
#define SNI_H

int parse_extensions(const uint8_t*, size_t, char **);
int parse_server_name_extension(const uint8_t*, size_t, char **);

#endif
Loading