Skip to content

Commit

Permalink
Implement custom extensions.
Browse files Browse the repository at this point in the history
This change mirrors upstream's custom extension API because we have some
internal users that depend on it.

Change-Id: I408e442de0a55df7b05c872c953ff048cd406513
Reviewed-on: https://boringssl-review.googlesource.com/5471
Reviewed-by: Adam Langley <agl@google.com>
  • Loading branch information
agl committed Jul 31, 2015
1 parent 30bff60 commit 0950563
Show file tree
Hide file tree
Showing 19 changed files with 744 additions and 9 deletions.
2 changes: 2 additions & 0 deletions crypto/err/ssl.errordata
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ SSL,134,CLIENTHELLO_TLSEXT
SSL,135,CONNECTION_REJECTED
SSL,136,CONNECTION_TYPE_NOT_SET
SSL,137,COOKIE_MISMATCH
SSL,284,CUSTOM_EXTENSION_CONTENTS_TOO_LARGE
SSL,285,CUSTOM_EXTENSION_ERROR
SSL,138,D2I_ECDSA_SIG
SSL,139,DATA_BETWEEN_CCS_AND_FINISHED
SSL,140,DATA_LENGTH_TOO_LONG
Expand Down
1 change: 1 addition & 0 deletions include/openssl/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ typedef struct sha256_state_st SHA256_CTX;
typedef struct sha512_state_st SHA512_CTX;
typedef struct sha_state_st SHA_CTX;
typedef struct ssl_ctx_st SSL_CTX;
typedef struct ssl_custom_extension SSL_CUSTOM_EXTENSION;
typedef struct ssl_st SSL;
typedef struct st_ERR_FNS ERR_FNS;
typedef struct v3_ext_ctx X509V3_CTX;
Expand Down
92 changes: 92 additions & 0 deletions include/openssl/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,92 @@ OPENSSL_EXPORT int SSL_get_tls_unique(const SSL *ssl, uint8_t *out,
size_t *out_len, size_t max_out);


/* Custom extensions.
*
* The custom extension functions allow TLS extensions to be added to
* ClientHello and ServerHello messages. */

/* SSL_custom_ext_add_cb is a callback function that is called when the
* ClientHello (for clients) or ServerHello (for servers) is constructed. In
* the case of a server, this callback will only be called for a given
* extension if the ClientHello contained that extension – it's not possible to
* inject extensions into a ServerHello that the client didn't request.
*
* When called, |extension_value| will contain the extension number that is
* being considered for addition (so that a single callback can handle multiple
* extensions). If the callback wishes to include the extension, it must set
* |*out| to point to |*out_len| bytes of extension contents and return one. In
* this case, the corresponding |SSL_custom_ext_free_cb| callback will later be
* called with the value of |*out| once that data has been copied.
*
* If the callback does not wish to add an extension it must return zero.
*
* Alternatively, the callback can abort the connection by setting
* |*out_alert_value| to a TLS alert number and returning -1. */
typedef int (*SSL_custom_ext_add_cb)(SSL *ssl, unsigned extension_value,
const uint8_t **out, size_t *out_len,
int *out_alert_value, void *add_arg);

/* SSL_custom_ext_free_cb is a callback function that is called by OpenSSL iff
* an |SSL_custom_ext_add_cb| callback previously returned one. In that case,
* this callback is called and passed the |out| pointer that was returned by
* the add callback. This is to free any dynamically allocated data created by
* the add callback. */
typedef void (*SSL_custom_ext_free_cb)(SSL *ssl, unsigned extension_value,
const uint8_t *out, void *add_arg);

/* SSL_custom_ext_parse_cb is a callback function that is called by OpenSSL to
* parse an extension from the peer: that is from the ServerHello for a client
* and from the ClientHello for a server.
*
* When called, |extension_value| will contain the extension number and the
* contents of the extension are |contents_len| bytes at |contents|.
*
* The callback must return one to continue the handshake. Otherwise, if it
* returns zero, a fatal alert with value |*out_alert_value| is sent and the
* handshake is aborted. */
typedef int (*SSL_custom_ext_parse_cb)(SSL *ssl, unsigned extension_value,
const uint8_t *contents,
size_t contents_len,
int *out_alert_value, void *parse_arg);

/* SSL_extension_supported returns one iff OpenSSL internally handles
* extensions of type |extension_value|. This can be used to avoid registering
* custom extension handlers for extensions that a future version of OpenSSL
* may handle internally. */
OPENSSL_EXPORT int SSL_extension_supported(unsigned extension_value);

/* SSL_CTX_add_client_custom_ext registers callback functions for handling
* custom TLS extensions for client connections.
*
* If |add_cb| is NULL then an empty extension will be added in each
* ClientHello. Otherwise, see the comment for |SSL_custom_ext_add_cb| about
* this callback.
*
* The |free_cb| may be NULL if |add_cb| doesn't dynamically allocate data that
* needs to be freed.
*
* It returns one on success or zero on error. It's always an error to register
* callbacks for the same extension twice, or to register callbacks for an
* extension that OpenSSL handles internally. See |SSL_extension_supported| to
* discover, at runtime, which extensions OpenSSL handles internally. */
OPENSSL_EXPORT int SSL_CTX_add_client_custom_ext(
SSL_CTX *ctx, unsigned extension_value, SSL_custom_ext_add_cb add_cb,
SSL_custom_ext_free_cb free_cb, void *add_arg,
SSL_custom_ext_parse_cb parse_cb, void *parse_arg);

/* SSL_CTX_add_server_custom_ext is the same as
* |SSL_CTX_add_client_custom_ext|, but for server connections.
*
* Unlike on the client side, if |add_cb| is NULL no extension will be added.
* The |add_cb|, if any, will only be called if the ClientHello contained a
* matching extension. */
OPENSSL_EXPORT int SSL_CTX_add_server_custom_ext(
SSL_CTX *ctx, unsigned extension_value, SSL_custom_ext_add_cb add_cb,
SSL_custom_ext_free_cb free_cb, void *add_arg,
SSL_custom_ext_parse_cb parse_cb, void *parse_arg);


/* Session tickets. */

/* SSL_CTX_get_tlsext_ticket_keys writes |ctx|'s session ticket key material to
Expand Down Expand Up @@ -1221,6 +1307,10 @@ struct ssl_ctx_st {

CRYPTO_EX_DATA ex_data;

/* custom_*_extensions stores any callback sets for custom extensions. Note
* that these pointers will be NULL if the stack would otherwise be empty. */
STACK_OF(SSL_CUSTOM_EXTENSION) *client_custom_extensions;
STACK_OF(SSL_CUSTOM_EXTENSION) *server_custom_extensions;

/* Default values used when no per-SSL value is defined follow */

Expand Down Expand Up @@ -2945,6 +3035,8 @@ OPENSSL_EXPORT const char *SSLeay_version(int unused);
#define SSL_R_ERROR_ADDING_EXTENSION 281
#define SSL_R_ERROR_PARSING_EXTENSION 282
#define SSL_R_MISSING_EXTENSION 283
#define SSL_R_CUSTOM_EXTENSION_CONTENTS_TOO_LARGE 284
#define SSL_R_CUSTOM_EXTENSION_ERROR 285
#define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
Expand Down
10 changes: 10 additions & 0 deletions include/openssl/ssl3.h
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,16 @@ typedef struct ssl3_state_st {
uint32_t received;
} extensions;

union {
/* sent is a bitset where the bits correspond to elements of
* |client_custom_extensions| in the |SSL_CTX|. Each bit is set if that
* extension was sent in a ClientHello. It's not used by servers. */
uint16_t sent;
/* received is a bitset, like |sent|, but is used by servers to record
* which custom extensions were received from a client. The bits here
* correspond to |server_custom_extensions|. */
uint16_t received;
} custom_extensions;

/* SNI extension */

Expand Down
1 change: 1 addition & 0 deletions include/openssl/stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ STACK_OF(type) {\
* STACK_OF:POLICY_MAPPING
* STACK_OF:RSA_additional_prime
* STACK_OF:SSL_COMP
* STACK_OF:SSL_CUSTOM_EXTENSION
* STACK_OF:STACK_OF_X509_NAME_ENTRY
* STACK_OF:SXNETID
* STACK_OF:X509
Expand Down
93 changes: 93 additions & 0 deletions include/openssl/stack_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -2106,6 +2106,99 @@
CHECKED_CAST(void *(*)(void *), SSL_COMP *(*)(SSL_COMP *), copy_func), \
CHECKED_CAST(void (*)(void *), void (*)(SSL_COMP *), free_func)))

/* SSL_CUSTOM_EXTENSION */
#define sk_SSL_CUSTOM_EXTENSION_new(comp) \
((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_new(CHECKED_CAST( \
stack_cmp_func, \
int (*)(const SSL_CUSTOM_EXTENSION **a, const SSL_CUSTOM_EXTENSION **b), \
comp)))

#define sk_SSL_CUSTOM_EXTENSION_new_null() \
((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_new_null())

#define sk_SSL_CUSTOM_EXTENSION_num(sk) \
sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))

#define sk_SSL_CUSTOM_EXTENSION_zero(sk) \
sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk));

#define sk_SSL_CUSTOM_EXTENSION_value(sk, i) \
((SSL_CUSTOM_EXTENSION *)sk_value( \
CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \
(i)))

#define sk_SSL_CUSTOM_EXTENSION_set(sk, i, p) \
((SSL_CUSTOM_EXTENSION *)sk_set( \
CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), (i), \
CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p)))

#define sk_SSL_CUSTOM_EXTENSION_free(sk) \
sk_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))

#define sk_SSL_CUSTOM_EXTENSION_pop_free(sk, free_func) \
sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \
CHECKED_CAST(void (*)(void *), void (*)(SSL_CUSTOM_EXTENSION *), \
free_func))

#define sk_SSL_CUSTOM_EXTENSION_insert(sk, p, where) \
sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \
CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p), (where))

#define sk_SSL_CUSTOM_EXTENSION_delete(sk, where) \
((SSL_CUSTOM_EXTENSION *)sk_delete( \
CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), (where)))

#define sk_SSL_CUSTOM_EXTENSION_delete_ptr(sk, p) \
((SSL_CUSTOM_EXTENSION *)sk_delete_ptr( \
CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \
CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p)))

#define sk_SSL_CUSTOM_EXTENSION_find(sk, out_index, p) \
sk_find(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \
(out_index), CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p))

#define sk_SSL_CUSTOM_EXTENSION_shift(sk) \
((SSL_CUSTOM_EXTENSION *)sk_shift( \
CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)))

#define sk_SSL_CUSTOM_EXTENSION_push(sk, p) \
sk_push(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \
CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p))

#define sk_SSL_CUSTOM_EXTENSION_pop(sk) \
((SSL_CUSTOM_EXTENSION *)sk_pop( \
CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)))

#define sk_SSL_CUSTOM_EXTENSION_dup(sk) \
((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_dup( \
CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)))

#define sk_SSL_CUSTOM_EXTENSION_sort(sk) \
sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))

#define sk_SSL_CUSTOM_EXTENSION_is_sorted(sk) \
sk_is_sorted( \
CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))

#define sk_SSL_CUSTOM_EXTENSION_set_cmp_func(sk, comp) \
((int (*)(const SSL_CUSTOM_EXTENSION **a, const SSL_CUSTOM_EXTENSION **b)) \
sk_set_cmp_func( \
CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \
CHECKED_CAST(stack_cmp_func, \
int (*)(const SSL_CUSTOM_EXTENSION **a, \
const SSL_CUSTOM_EXTENSION **b), \
comp)))

#define sk_SSL_CUSTOM_EXTENSION_deep_copy(sk, copy_func, free_func) \
((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_deep_copy( \
CHECKED_CAST(const _STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, \
sk), \
CHECKED_CAST(void *(*)(void *), \
SSL_CUSTOM_EXTENSION *(*)(SSL_CUSTOM_EXTENSION *), \
copy_func), \
CHECKED_CAST(void (*)(void *), void (*)(SSL_CUSTOM_EXTENSION *), \
free_func)))

/* STACK_OF_X509_NAME_ENTRY */
#define sk_STACK_OF_X509_NAME_ENTRY_new(comp) \
((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_new(CHECKED_CAST( \
Expand Down
1 change: 1 addition & 0 deletions ssl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_subdirectory(pqueue)
add_library(
ssl

custom_extensions.c
d1_both.c
d1_clnt.c
d1_lib.c
Expand Down
Loading

0 comments on commit 0950563

Please sign in to comment.