diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index b3be3e12..b68db3d6 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -209,7 +209,7 @@ extern "C" { #define TLSEXT_TYPE_signature_algorithms 13 /* ExtensionType value from RFC5764 */ -#define TLSEXT_TYPE_use_srtp 14 +#define TLSEXT_TYPE_srtp 14 /* ExtensionType value from RFC5620 */ #define TLSEXT_TYPE_heartbeat 15 diff --git a/ssl/d1_srtp.c b/ssl/d1_srtp.c index a698b105..48ecfb21 100644 --- a/ssl/d1_srtp.c +++ b/ssl/d1_srtp.c @@ -125,12 +125,12 @@ #include -static const SRTP_PROTECTION_PROFILE srtp_known_profiles[] = { +const SRTP_PROTECTION_PROFILE kSRTPProfiles[] = { { - "SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, + "SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, }, { - "SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, + "SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, }, {0}, }; @@ -140,7 +140,7 @@ static int find_profile_by_name(const char *profile_name, size_t len) { const SRTP_PROTECTION_PROFILE *p; - p = srtp_known_profiles; + p = kSRTPProfiles; while (p->name) { if (len == strlen(p->name) && !strncmp(p->name, profile_name, len)) { *pptr = p; @@ -153,22 +153,6 @@ static int find_profile_by_name(const char *profile_name, return 0; } -static int find_profile_by_num(unsigned profile_num, - const SRTP_PROTECTION_PROFILE **pptr) { - const SRTP_PROTECTION_PROFILE *p; - - p = srtp_known_profiles; - while (p->name) { - if (p->id == profile_num) { - *pptr = p; - return 1; - } - p++; - } - - return 0; -} - static int ssl_ctx_make_profiles(const char *profiles_string, STACK_OF(SRTP_PROTECTION_PROFILE) **out) { STACK_OF(SRTP_PROTECTION_PROFILE) *profiles; @@ -240,181 +224,3 @@ int SSL_set_tlsext_use_srtp(SSL *s, const char *profiles) { /* This API inverts its return value. */ return !SSL_set_srtp_profiles(s, profiles); } - -/* Note: this function returns 0 length if there are no profiles specified */ -int ssl_add_clienthello_use_srtp_ext(SSL *s, uint8_t *p, int *len, int maxlen) { - int ct = 0; - int i; - STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = 0; - const SRTP_PROTECTION_PROFILE *prof; - - clnt = SSL_get_srtp_profiles(s); - ct = sk_SRTP_PROTECTION_PROFILE_num(clnt); /* -1 if clnt == 0 */ - - if (p) { - if (ct == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST); - return 0; - } - - if (2 + ct * 2 + 1 > maxlen) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG); - return 0; - } - - /* Add the length */ - s2n(ct * 2, p); - for (i = 0; i < ct; i++) { - prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i); - s2n(prof->id, p); - } - - /* Add an empty use_mki value */ - *p++ = 0; - } - - *len = 2 + ct * 2 + 1; - - return 1; -} - -int ssl_parse_clienthello_use_srtp_ext(SSL *s, CBS *cbs, int *out_alert) { - CBS profile_ids, srtp_mki; - const SRTP_PROTECTION_PROFILE *cprof, *sprof; - STACK_OF(SRTP_PROTECTION_PROFILE) *client_profiles = 0, *server_profiles; - size_t i, j; - int ret = 0; - - if (!CBS_get_u16_length_prefixed(cbs, &profile_ids) || - CBS_len(&profile_ids) < 2 || - !CBS_get_u8_length_prefixed(cbs, &srtp_mki) || - CBS_len(cbs) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *out_alert = SSL_AD_DECODE_ERROR; - goto done; - } - - client_profiles = sk_SRTP_PROTECTION_PROFILE_new_null(); - if (client_profiles == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - *out_alert = SSL_AD_INTERNAL_ERROR; - goto done; - } - - while (CBS_len(&profile_ids) > 0) { - uint16_t profile_id; - - if (!CBS_get_u16(&profile_ids, &profile_id)) { - *out_alert = SSL_AD_DECODE_ERROR; - goto done; - } - - if (find_profile_by_num(profile_id, &cprof)) { - sk_SRTP_PROTECTION_PROFILE_push(client_profiles, cprof); - } - } - - /* Discard the MKI value for now. */ - - server_profiles = SSL_get_srtp_profiles(s); - - /* Pick the server's most preferred profile. */ - for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(server_profiles); i++) { - sprof = sk_SRTP_PROTECTION_PROFILE_value(server_profiles, i); - - for (j = 0; j < sk_SRTP_PROTECTION_PROFILE_num(client_profiles); j++) { - cprof = sk_SRTP_PROTECTION_PROFILE_value(client_profiles, j); - - if (cprof->id == sprof->id) { - s->srtp_profile = sprof; - ret = 1; - goto done; - } - } - } - - ret = 1; - -done: - if (client_profiles) { - sk_SRTP_PROTECTION_PROFILE_free(client_profiles); - } - - return ret; -} - -int ssl_add_serverhello_use_srtp_ext(SSL *s, unsigned char *p, int *len, - int maxlen) { - if (p) { - if (maxlen < 5) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG); - return 0; - } - - if (s->srtp_profile == 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_USE_SRTP_NOT_NEGOTIATED); - return 0; - } - - s2n(2, p); - s2n(s->srtp_profile->id, p); - *p++ = 0; - } - - *len = 5; - - return 1; -} - -int ssl_parse_serverhello_use_srtp_ext(SSL *s, CBS *cbs, int *out_alert) { - CBS profile_ids, srtp_mki; - uint16_t profile_id; - size_t i; - - STACK_OF(SRTP_PROTECTION_PROFILE) *client_profiles; - const SRTP_PROTECTION_PROFILE *prof; - - /* The extension consists of a u16-prefixed profile ID list containing a - * single uint16_t profile ID, then followed by a u8-prefixed srtp_mki field. - * - * See https://tools.ietf.org/html/rfc5764#section-4.1.1 */ - if (!CBS_get_u16_length_prefixed(cbs, &profile_ids) || - !CBS_get_u16(&profile_ids, &profile_id) || CBS_len(&profile_ids) != 0 || - !CBS_get_u8_length_prefixed(cbs, &srtp_mki) || CBS_len(cbs) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } - - if (CBS_len(&srtp_mki) != 0) { - /* Must be no MKI, since we never offer one. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_MKI_VALUE); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } - - client_profiles = SSL_get_srtp_profiles(s); - - /* Throw an error if the server gave us an unsolicited extension */ - if (client_profiles == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SRTP_PROFILES); - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } - - /* Check to see if the server gave us something we support - (and presumably offered). */ - for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(client_profiles); i++) { - prof = sk_SRTP_PROTECTION_PROFILE_value(client_profiles, i); - - if (prof->id == profile_id) { - s->srtp_profile = prof; - *out_alert = 0; - return 1; - } - } - - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; -} diff --git a/ssl/internal.h b/ssl/internal.h index f107452e..1a28245f 100644 --- a/ssl/internal.h +++ b/ssl/internal.h @@ -1168,9 +1168,4 @@ int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s, CBS *cbs, EVP_PKEY *pkey); void ssl_set_client_disabled(SSL *s); -int ssl_add_clienthello_use_srtp_ext(SSL *s, uint8_t *p, int *len, int maxlen); -int ssl_parse_clienthello_use_srtp_ext(SSL *s, CBS *cbs, int *out_alert); -int ssl_add_serverhello_use_srtp_ext(SSL *s, uint8_t *p, int *len, int maxlen); -int ssl_parse_serverhello_use_srtp_ext(SSL *s, CBS *cbs, int *out_alert); - #endif /* OPENSSL_HEADER_SSL_INTERNAL_H */ diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 4551025a..9b64c7b6 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -1760,6 +1760,160 @@ static int ext_channel_id_add_serverhello(SSL *ssl, CBB *out) { return 1; } + +/* Secure Real-time Transport Protocol (SRTP) extension. + * + * https://tools.ietf.org/html/rfc5764 */ + +extern const SRTP_PROTECTION_PROFILE kSRTPProfiles[]; + +static void ext_srtp_init(SSL *ssl) { + ssl->srtp_profile = NULL; +} + +static int ext_srtp_add_clienthello(SSL *ssl, CBB *out) { + STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl); + if (profiles == NULL) { + return 1; + } + const size_t num_profiles = sk_SRTP_PROTECTION_PROFILE_num(profiles); + if (num_profiles == 0) { + return 1; + } + + CBB contents, profile_ids; + if (!CBB_add_u16(out, TLSEXT_TYPE_srtp) || + !CBB_add_u16_length_prefixed(out, &contents) || + !CBB_add_u16_length_prefixed(&contents, &profile_ids)) { + return 0; + } + + size_t i; + for (i = 0; i < num_profiles; i++) { + if (!CBB_add_u16(&profile_ids, + sk_SRTP_PROTECTION_PROFILE_value(profiles, i)->id)) { + return 0; + } + } + + if (!CBB_add_u8(&contents, 0 /* empty use_mki value */) || + !CBB_flush(out)) { + return 0; + } + + return 1; +} + +static int ext_srtp_parse_serverhello(SSL *ssl, uint8_t *out_alert, + CBS *contents) { + if (contents == NULL) { + return 1; + } + + /* The extension consists of a u16-prefixed profile ID list containing a + * single uint16_t profile ID, then followed by a u8-prefixed srtp_mki field. + * + * See https://tools.ietf.org/html/rfc5764#section-4.1.1 */ + CBS profile_ids, srtp_mki; + uint16_t profile_id; + if (!CBS_get_u16_length_prefixed(contents, &profile_ids) || + !CBS_get_u16(&profile_ids, &profile_id) || + CBS_len(&profile_ids) != 0 || + !CBS_get_u8_length_prefixed(contents, &srtp_mki) || + CBS_len(contents) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + return 0; + } + + if (CBS_len(&srtp_mki) != 0) { + /* Must be no MKI, since we never offer one. */ + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_MKI_VALUE); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl); + + /* Check to see if the server gave us something we support (and presumably + * offered). */ + size_t i; + for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(profiles); i++) { + const SRTP_PROTECTION_PROFILE *profile = + sk_SRTP_PROTECTION_PROFILE_value(profiles, i); + + if (profile->id == profile_id) { + ssl->srtp_profile = profile; + return 1; + } + } + + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; +} + +static int ext_srtp_parse_clienthello(SSL *ssl, uint8_t *out_alert, + CBS *contents) { + if (contents == NULL) { + return 1; + } + + CBS profile_ids, srtp_mki; + if (!CBS_get_u16_length_prefixed(contents, &profile_ids) || + CBS_len(&profile_ids) < 2 || + !CBS_get_u8_length_prefixed(contents, &srtp_mki) || + CBS_len(contents) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + return 0; + } + /* Discard the MKI value for now. */ + + const STACK_OF(SRTP_PROTECTION_PROFILE) *server_profiles = + SSL_get_srtp_profiles(ssl); + + /* Pick the server's most preferred profile. */ + size_t i; + for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(server_profiles); i++) { + const SRTP_PROTECTION_PROFILE *server_profile = + sk_SRTP_PROTECTION_PROFILE_value(server_profiles, i); + + CBS profile_ids_tmp; + CBS_init(&profile_ids_tmp, CBS_data(&profile_ids), CBS_len(&profile_ids)); + + while (CBS_len(&profile_ids_tmp) > 0) { + uint16_t profile_id; + if (!CBS_get_u16(&profile_ids_tmp, &profile_id)) { + return 0; + } + + if (server_profile->id == profile_id) { + ssl->srtp_profile = server_profile; + return 1; + } + } + } + + return 1; +} + +static int ext_srtp_add_serverhello(SSL *ssl, CBB *out) { + if (ssl->srtp_profile == NULL) { + return 1; + } + + CBB contents, profile_ids; + if (!CBB_add_u16(out, TLSEXT_TYPE_srtp) || + !CBB_add_u16_length_prefixed(out, &contents) || + !CBB_add_u16_length_prefixed(&contents, &profile_ids) || + !CBB_add_u16(&profile_ids, ssl->srtp_profile->id) || + !CBB_add_u8(&contents, 0 /* empty MKI */) || + !CBB_flush(out)) { + return 0; + } + + return 1; +} + /* kExtensions contains all the supported extensions. */ static const struct tls_extension kExtensions[] = { { @@ -1845,6 +1999,14 @@ static const struct tls_extension kExtensions[] = { ext_channel_id_parse_clienthello, ext_channel_id_add_serverhello, }, + { + TLSEXT_TYPE_srtp, + ext_srtp_init, + ext_srtp_add_clienthello, + ext_srtp_parse_serverhello, + ext_srtp_parse_clienthello, + ext_srtp_add_serverhello, + }, }; #define kNumExtensions (sizeof(kExtensions) / sizeof(struct tls_extension)) @@ -1941,25 +2103,6 @@ uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *const buf, ret += CBB_len(&cbb); CBB_cleanup(&cbb); - if (SSL_get_srtp_profiles(s)) { - int el; - - ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0); - - if ((limit - ret - 4 - el) < 0) { - return NULL; - } - - s2n(TLSEXT_TYPE_use_srtp, ret); - s2n(el, ret); - - if (!ssl_add_clienthello_use_srtp_ext(s, ret, &el, el)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return NULL; - } - ret += el; - } - if (using_ecc) { /* Add TLS extension ECPointFormats to the ClientHello message */ long lenmax; @@ -2133,25 +2276,6 @@ uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *const buf, } /* Currently the server should not respond with a SupportedCurves extension */ - if (s->srtp_profile) { - int el; - - ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0); - - if ((limit - ret - 4 - el) < 0) { - return NULL; - } - - s2n(TLSEXT_TYPE_use_srtp, ret); - s2n(el, ret); - - if (!ssl_add_serverhello_use_srtp_ext(s, ret, &el, el)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return NULL; - } - ret += el; - } - extdatalen = ret - orig - 2; if (extdatalen == 0) { return orig; @@ -2164,8 +2288,6 @@ uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *const buf, static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) { CBS extensions; - s->srtp_profile = NULL; - /* Clear ECC extensions */ OPENSSL_free(s->s3->tmp.peer_ecpointformatlist); s->s3->tmp.peer_ecpointformatlist = NULL; @@ -2278,10 +2400,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) { } s->s3->tmp.peer_ellipticcurvelist_length = num_curves; - } else if (type == TLSEXT_TYPE_use_srtp) { - if (!ssl_parse_clienthello_use_srtp_ext(s, &extension, out_alert)) { - return 0; - } } } @@ -2319,11 +2437,6 @@ int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs) { static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) { CBS extensions; - /* TODO(davidben): Move all of these to some per-handshake state that gets - * systematically reset on a new handshake; perhaps allocate it fresh each - * time so it's not even kept around post-handshake. */ - s->srtp_profile = NULL; - /* Clear ECC extensions */ OPENSSL_free(s->s3->tmp.peer_ecpointformatlist); s->s3->tmp.peer_ecpointformatlist = NULL; @@ -2397,10 +2510,6 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) { *out_alert = SSL_AD_INTERNAL_ERROR; return 0; } - } else if (type == TLSEXT_TYPE_use_srtp) { - if (!ssl_parse_serverhello_use_srtp_ext(s, &extension, out_alert)) { - return 0; - } } }