diff options
author | Doug Hogan <doug@cvs.openbsd.org> | 2017-08-27 02:58:05 +0000 |
---|---|---|
committer | Doug Hogan <doug@cvs.openbsd.org> | 2017-08-27 02:58:05 +0000 |
commit | d61818b0fc5a1152ce77b156e959f2e7fe9efa71 (patch) | |
tree | 222169016a1880d9c8d8be187fcc26e0f4912666 /lib/libssl | |
parent | 444ca10cca4b94aece92a2a80a817219b118825b (diff) |
Rewrite SRTP extension using CBB/CBS and the new extension framework.
input + ok beck@, jsing@
Diffstat (limited to 'lib/libssl')
-rw-r--r-- | lib/libssl/d1_srtp.c | 220 | ||||
-rw-r--r-- | lib/libssl/ssl_locl.h | 11 | ||||
-rw-r--r-- | lib/libssl/ssl_tlsext.c | 224 | ||||
-rw-r--r-- | lib/libssl/ssl_tlsext.h | 11 | ||||
-rw-r--r-- | lib/libssl/t1_lib.c | 58 |
5 files changed, 250 insertions, 274 deletions
diff --git a/lib/libssl/d1_srtp.c b/lib/libssl/d1_srtp.c index 26c14543fc9..eb1877a12c8 100644 --- a/lib/libssl/d1_srtp.c +++ b/lib/libssl/d1_srtp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: d1_srtp.c,v 1.21 2017/02/07 02:08:38 beck Exp $ */ +/* $OpenBSD: d1_srtp.c,v 1.22 2017/08/27 02:58:04 doug Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -138,8 +138,8 @@ static SRTP_PROTECTION_PROFILE srtp_known_profiles[] = { {0} }; -static int -find_profile_by_name(char *profile_name, SRTP_PROTECTION_PROFILE **pptr, +int +srtp_find_profile_by_name(char *profile_name, SRTP_PROTECTION_PROFILE **pptr, unsigned len) { SRTP_PROTECTION_PROFILE *p; @@ -158,8 +158,8 @@ find_profile_by_name(char *profile_name, SRTP_PROTECTION_PROFILE **pptr, return 1; } -static int -find_profile_by_num(unsigned profile_num, SRTP_PROTECTION_PROFILE **pptr) +int +srtp_find_profile_by_num(unsigned profile_num, SRTP_PROTECTION_PROFILE **pptr) { SRTP_PROTECTION_PROFILE *p; @@ -194,7 +194,7 @@ ssl_ctx_make_profiles(const char *profiles_string, do { col = strchr(ptr, ':'); - if (!find_profile_by_name(ptr, &p, + if (!srtp_find_profile_by_name(ptr, &p, col ? col - ptr : (int)strlen(ptr))) { sk_SRTP_PROTECTION_PROFILE_push(profiles, p); } else { @@ -246,212 +246,4 @@ SSL_get_selected_srtp_profile(SSL *s) return s->internal->srtp_profile; } -/* Note: this function returns 0 length if there are no - profiles specified */ -int -ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen) -{ - int ct = 0; - int i; - STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = 0; - 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) { - SSLerror(s, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST); - return 1; - } - - if ((2 + ct * 2 + 1) > maxlen) { - SSLerror(s, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG); - return 1; - } - - /* 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 0; -} - - -int -ssl_parse_clienthello_use_srtp_ext(SSL *s, const unsigned char *d, int len, - int *al) -{ - SRTP_PROTECTION_PROFILE *cprof, *sprof; - STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = 0, *srvr; - int i, j; - int ret = 1; - uint16_t id; - CBS cbs, ciphers, mki; - - if (len < 0) { - SSLerror(s, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *al = SSL_AD_DECODE_ERROR; - goto done; - } - - CBS_init(&cbs, d, len); - /* Pull off the cipher suite list */ - if (!CBS_get_u16_length_prefixed(&cbs, &ciphers) || - CBS_len(&ciphers) % 2) { - SSLerror(s, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *al = SSL_AD_DECODE_ERROR; - goto done; - } - - clnt = sk_SRTP_PROTECTION_PROFILE_new_null(); - - while (CBS_len(&ciphers) > 0) { - if (!CBS_get_u16(&ciphers, &id)) { - SSLerror(s, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *al = SSL_AD_DECODE_ERROR; - goto done; - } - - if (!find_profile_by_num(id, &cprof)) - sk_SRTP_PROTECTION_PROFILE_push(clnt, cprof); - else - ; /* Ignore */ - } - - /* Extract the MKI value as a sanity check, but discard it for now. */ - if (!CBS_get_u8_length_prefixed(&cbs, &mki) || - CBS_len(&cbs) != 0) { - SSLerror(s, SSL_R_BAD_SRTP_MKI_VALUE); - *al = SSL_AD_DECODE_ERROR; - goto done; - } - - srvr = SSL_get_srtp_profiles(s); - - /* - * Pick our most preferred profile. If no profiles have been - * configured then the outer loop doesn't run - * (sk_SRTP_PROTECTION_PROFILE_num() = -1) - * and so we just return without doing anything. - */ - for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(srvr); i++) { - sprof = sk_SRTP_PROTECTION_PROFILE_value(srvr, i); - - for (j = 0; j < sk_SRTP_PROTECTION_PROFILE_num(clnt); j++) { - cprof = sk_SRTP_PROTECTION_PROFILE_value(clnt, j); - - if (cprof->id == sprof->id) { - s->internal->srtp_profile = sprof; - *al = 0; - ret = 0; - goto done; - } - } - } - - ret = 0; - -done: - sk_SRTP_PROTECTION_PROFILE_free(clnt); - - return ret; -} - -int -ssl_add_serverhello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen) -{ - if (p) { - if (maxlen < 5) { - SSLerror(s, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG); - return 1; - } - - if (s->internal->srtp_profile == 0) { - SSLerror(s, SSL_R_USE_SRTP_NOT_NEGOTIATED); - return 1; - } - s2n(2, p); - s2n(s->internal->srtp_profile->id, p); - *p++ = 0; - } - *len = 5; - - return 0; -} - - -int -ssl_parse_serverhello_use_srtp_ext(SSL *s, const unsigned char *d, int len, int *al) -{ - STACK_OF(SRTP_PROTECTION_PROFILE) *clnt; - SRTP_PROTECTION_PROFILE *prof; - int i; - uint16_t id; - CBS cbs, profile_ids, mki; - - if (len < 0) { - SSLerror(s, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *al = SSL_AD_DECODE_ERROR; - return 1; - } - - CBS_init(&cbs, d, len); - - /* - * As per RFC 5764 section 4.1.1, server response MUST be a single - * profile id. - */ - if (!CBS_get_u16_length_prefixed(&cbs, &profile_ids) || - !CBS_get_u16(&profile_ids, &id) || CBS_len(&profile_ids) != 0) { - SSLerror(s, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *al = SSL_AD_DECODE_ERROR; - return 1; - } - - /* Must be no MKI, since we never offer one. */ - if (!CBS_get_u8_length_prefixed(&cbs, &mki) || CBS_len(&mki) != 0) { - SSLerror(s, SSL_R_BAD_SRTP_MKI_VALUE); - *al = SSL_AD_ILLEGAL_PARAMETER; - return 1; - } - - clnt = SSL_get_srtp_profiles(s); - - /* Throw an error if the server gave us an unsolicited extension. */ - if (clnt == NULL) { - SSLerror(s, SSL_R_NO_SRTP_PROFILES); - *al = SSL_AD_DECODE_ERROR; - return 1; - } - - /* - * Check to see if the server gave us something we support - * (and presumably offered). - */ - for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(clnt); i++) { - prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i); - - if (prof->id == id) { - s->internal->srtp_profile = prof; - *al = 0; - return 0; - } - } - - SSLerror(s, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *al = SSL_AD_DECODE_ERROR; - return 1; -} - #endif diff --git a/lib/libssl/ssl_locl.h b/lib/libssl/ssl_locl.h index 624df9c929c..e789a4ae272 100644 --- a/lib/libssl/ssl_locl.h +++ b/lib/libssl/ssl_locl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_locl.h,v 1.191 2017/08/26 20:23:46 doug Exp $ */ +/* $OpenBSD: ssl_locl.h,v 1.192 2017/08/27 02:58:04 doug Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1348,6 +1348,15 @@ void tls1_get_formatlist(SSL *s, int client_formats, const uint8_t **pformats, void tls1_get_curvelist(SSL *s, int client_curves, const uint16_t **pcurves, size_t *pcurveslen); +#ifndef OPENSSL_NO_SRTP + +int srtp_find_profile_by_name(char *profile_name, + SRTP_PROTECTION_PROFILE **pptr, unsigned len); +int srtp_find_profile_by_num(unsigned profile_num, + SRTP_PROTECTION_PROFILE **pptr); + +#endif /* OPENSSL_NO_SRTP */ + __END_HIDDEN_DECLS #endif diff --git a/lib/libssl/ssl_tlsext.c b/lib/libssl/ssl_tlsext.c index 405882c0e9b..2438b90d040 100644 --- a/lib/libssl/ssl_tlsext.c +++ b/lib/libssl/ssl_tlsext.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_tlsext.c,v 1.11 2017/08/26 20:23:46 doug Exp $ */ +/* $OpenBSD: ssl_tlsext.c,v 1.12 2017/08/27 02:58:04 doug Exp $ */ /* * Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org> * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> @@ -704,6 +704,7 @@ tlsext_sni_serverhello_parse(SSL *s, CBS *cbs, int *alert) return 1; } + /* *Certificate Status Request - RFC 6066 section 8. */ @@ -983,6 +984,216 @@ tlsext_sessionticket_serverhello_parse(SSL *s, CBS *cbs, int *alert) return 1; } +/* + * DTLS extension for SRTP key establishment - RFC 5764 + */ + +#ifndef OPENSSL_NO_SRTP + +int +tlsext_srtp_clienthello_needs(SSL *s) +{ + return SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s) != NULL; +} + +int +tlsext_srtp_clienthello_build(SSL *s, CBB *cbb) +{ + CBB profiles, mki; + int ct, i; + STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = NULL; + SRTP_PROTECTION_PROFILE *prof; + + if ((clnt = SSL_get_srtp_profiles(s)) == NULL) { + SSLerror(s, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST); + return 0; + } + + if ((ct = sk_SRTP_PROTECTION_PROFILE_num(clnt)) < 1) { + SSLerror(s, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST); + return 0; + } + + if (!CBB_add_u16_length_prefixed(cbb, &profiles)) + return 0; + + for (i = 0; i < ct; i++) { + if ((prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i)) == NULL) + return 0; + if (!CBB_add_u16(&profiles, prof->id)) + return 0; + } + + if (!CBB_add_u8_length_prefixed(cbb, &mki)) + return 0; + + if (!CBB_flush(cbb)) + return 0; + + return 1; +} + +int +tlsext_srtp_clienthello_parse(SSL *s, CBS *cbs, int *alert) +{ + SRTP_PROTECTION_PROFILE *cprof, *sprof; + STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = NULL, *srvr; + int i, j; + int ret; + uint16_t id; + CBS profiles, mki; + + ret = 0; + + if (!CBS_get_u16_length_prefixed(cbs, &profiles)) + goto err; + if (CBS_len(&profiles) == 0 || CBS_len(&profiles) % 2 != 0) + goto err; + + if ((clnt = sk_SRTP_PROTECTION_PROFILE_new_null()) == NULL) + goto err; + + while (CBS_len(&profiles) > 0) { + if (!CBS_get_u16(&profiles, &id)) + goto err; + + if (!srtp_find_profile_by_num(id, &cprof)) { + if (!sk_SRTP_PROTECTION_PROFILE_push(clnt, cprof)) + goto err; + } + } + + if (!CBS_get_u8_length_prefixed(cbs, &mki) || CBS_len(&mki) != 0) { + SSLerror(s, SSL_R_BAD_SRTP_MKI_VALUE); + *alert = SSL_AD_DECODE_ERROR; + goto done; + } + if (CBS_len(cbs) != 0) + goto err; + + /* + * Per RFC 5764 section 4.1.1 + * + * Find the server preferred profile using the client's list. + * + * The server MUST send a profile if it sends the use_srtp + * extension. If one is not found, it should fall back to the + * negotiated DTLS cipher suite or return a DTLS alert. + */ + if ((srvr = SSL_get_srtp_profiles(s)) == NULL) + goto err; + for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(srvr); i++) { + if ((sprof = sk_SRTP_PROTECTION_PROFILE_value(srvr, i)) + == NULL) + goto err; + + for (j = 0; j < sk_SRTP_PROTECTION_PROFILE_num(clnt); j++) { + if ((cprof = sk_SRTP_PROTECTION_PROFILE_value(clnt, j)) + == NULL) + goto err; + + if (cprof->id == sprof->id) { + s->internal->srtp_profile = sprof; + ret = 1; + goto done; + } + } + } + + /* If we didn't find anything, fall back to the negotiated */ + ret = 1; + goto done; + + err: + SSLerror(s, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *alert = SSL_AD_DECODE_ERROR; + + done: + sk_SRTP_PROTECTION_PROFILE_free(clnt); + return ret; +} + +int +tlsext_srtp_serverhello_needs(SSL *s) +{ + return SSL_IS_DTLS(s) && SSL_get_selected_srtp_profile(s) != NULL; +} + +int +tlsext_srtp_serverhello_build(SSL *s, CBB *cbb) +{ + SRTP_PROTECTION_PROFILE *profile; + CBB srtp, mki; + + if (!CBB_add_u16_length_prefixed(cbb, &srtp)) + return 0; + + if ((profile = SSL_get_selected_srtp_profile(s)) == NULL) + return 0; + + if (!CBB_add_u16(&srtp, profile->id)) + return 0; + + if (!CBB_add_u8_length_prefixed(cbb, &mki)) + return 0; + + if (!CBB_flush(cbb)) + return 0; + + return 1; +} + +int +tlsext_srtp_serverhello_parse(SSL *s, CBS *cbs, int *alert) +{ + STACK_OF(SRTP_PROTECTION_PROFILE) *clnt; + SRTP_PROTECTION_PROFILE *prof; + int i; + uint16_t id; + CBS profile_ids, mki; + + if (!CBS_get_u16_length_prefixed(cbs, &profile_ids)) { + SSLerror(s, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + goto err; + } + + if (!CBS_get_u16(&profile_ids, &id) || CBS_len(&profile_ids) != 0) { + SSLerror(s, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + goto err; + } + + if (!CBS_get_u8_length_prefixed(cbs, &mki) || CBS_len(&mki) != 0) { + SSLerror(s, SSL_R_BAD_SRTP_MKI_VALUE); + *alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + if ((clnt = SSL_get_srtp_profiles(s)) == NULL) { + SSLerror(s, SSL_R_NO_SRTP_PROFILES); + goto err; + } + + for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(clnt); i++) { + if ((prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i)) + == NULL) { + SSLerror(s, SSL_R_NO_SRTP_PROFILES); + goto err; + } + + if (prof->id == id) { + s->internal->srtp_profile = prof; + return 1; + } + } + + SSLerror(s, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + err: + *alert = SSL_AD_DECODE_ERROR; + return 0; +} + +#endif /* OPENSSL_NO_SRTP */ + struct tls_extension { uint16_t type; int (*clienthello_needs)(SSL *s); @@ -1066,6 +1277,17 @@ static struct tls_extension tls_extensions[] = { .serverhello_build = tlsext_alpn_serverhello_build, .serverhello_parse = tlsext_alpn_serverhello_parse, }, +#ifndef OPENSSL_NO_SRTP + { + .type = TLSEXT_TYPE_use_srtp, + .clienthello_needs = tlsext_srtp_clienthello_needs, + .clienthello_build = tlsext_srtp_clienthello_build, + .clienthello_parse = tlsext_srtp_clienthello_parse, + .serverhello_needs = tlsext_srtp_serverhello_needs, + .serverhello_build = tlsext_srtp_serverhello_build, + .serverhello_parse = tlsext_srtp_serverhello_parse, + } +#endif /* OPENSSL_NO_SRTP */ }; #define N_TLS_EXTENSIONS (sizeof(tls_extensions) / sizeof(*tls_extensions)) diff --git a/lib/libssl/ssl_tlsext.h b/lib/libssl/ssl_tlsext.h index 21f9bb1bf93..7c6250a7f7d 100644 --- a/lib/libssl/ssl_tlsext.h +++ b/lib/libssl/ssl_tlsext.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_tlsext.h,v 1.9 2017/08/26 20:23:46 doug Exp $ */ +/* $OpenBSD: ssl_tlsext.h,v 1.10 2017/08/27 02:58:04 doug Exp $ */ /* * Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org> * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> @@ -72,6 +72,15 @@ int tlsext_sessionticket_serverhello_needs(SSL *s); int tlsext_sessionticket_serverhello_build(SSL *s, CBB *cbb); int tlsext_sessionticket_serverhello_parse(SSL *s, CBS *cbs, int *alert); +#ifndef OPENSSL_NO_SRTP +int tlsext_srtp_clienthello_needs(SSL *s); +int tlsext_srtp_clienthello_build(SSL *s, CBB *cbb); +int tlsext_srtp_clienthello_parse(SSL *s, CBS *cbs, int *alert); +int tlsext_srtp_serverhello_needs(SSL *s); +int tlsext_srtp_serverhello_build(SSL *s, CBB *cbb); +int tlsext_srtp_serverhello_parse(SSL *s, CBS *cbs, int *alert); +#endif + int tlsext_clienthello_build(SSL *s, CBB *cbb); int tlsext_clienthello_parse_one(SSL *s, CBS *cbs, uint16_t tlsext_type, int *alert); diff --git a/lib/libssl/t1_lib.c b/lib/libssl/t1_lib.c index eb1d96cc11a..a9f10166fe4 100644 --- a/lib/libssl/t1_lib.c +++ b/lib/libssl/t1_lib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: t1_lib.c,v 1.135 2017/08/26 20:23:46 doug Exp $ */ +/* $OpenBSD: t1_lib.c,v 1.136 2017/08/27 02:58:04 doug Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -687,26 +687,6 @@ ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) return NULL; ret += len; -#ifndef OPENSSL_NO_SRTP - if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s)) { - int el; - - ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0); - - if ((size_t)(limit - ret) < 4 + el) - return NULL; - - s2n(TLSEXT_TYPE_use_srtp, ret); - s2n(el, ret); - - if (ssl_add_clienthello_use_srtp_ext(s, ret, &el, el)) { - SSLerror(s, ERR_R_INTERNAL_ERROR); - return NULL; - } - ret += el; - } -#endif - if ((extdatalen = ret - p - 2) == 0) return p; @@ -745,26 +725,6 @@ ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) * extension. */ -#ifndef OPENSSL_NO_SRTP - if (SSL_IS_DTLS(s) && s->internal->srtp_profile) { - int el; - - ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0); - - if ((size_t)(limit - ret) < 4 + el) - return NULL; - - s2n(TLSEXT_TYPE_use_srtp, ret); - s2n(el, ret); - - if (ssl_add_serverhello_use_srtp_ext(s, ret, &el, el)) { - SSLerror(s, ERR_R_INTERNAL_ERROR); - return NULL; - } - ret += el; - } -#endif - if ((extdatalen = ret - p - 2) == 0) return p; @@ -815,14 +775,6 @@ ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, if (!tlsext_clienthello_parse_one(s, &cbs, type, al)) return 0; - /* session ticket processed earlier */ -#ifndef OPENSSL_NO_SRTP - else if (SSL_IS_DTLS(s) && type == TLSEXT_TYPE_use_srtp) { - if (ssl_parse_clienthello_use_srtp_ext(s, data, size, al)) - return 0; - } -#endif - data += size; } @@ -888,14 +840,6 @@ ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, size_t n, int *al) if (!tlsext_serverhello_parse_one(s, &cbs, type, al)) return 0; -#ifndef OPENSSL_NO_SRTP - else if (SSL_IS_DTLS(s) && type == TLSEXT_TYPE_use_srtp) { - if (ssl_parse_serverhello_use_srtp_ext(s, data, - size, al)) - return 0; - } -#endif - data += size; } |