Allow dtls_seal_record to work in-place. This will let us avoid a scratch buffer when assembling DTLS handshake packets in the write_message-less flow. BUG=72 Change-Id: I15e78efe3a9e3933c307e599f0043427330f4a9e Reviewed-on: https://boringssl-review.googlesource.com/13262 Commit-Queue: David Benjamin <davidben@google.com> Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/dtls_record.c b/ssl/dtls_record.c index e507f5c..35c08b0 100644 --- a/ssl/dtls_record.c +++ b/ssl/dtls_record.c
@@ -249,10 +249,24 @@ return ssl_open_record_success; } +size_t dtls_seal_prefix_len(const SSL *ssl, enum dtls1_use_epoch_t use_epoch) { + const SSL_AEAD_CTX *aead = ssl->s3->aead_write_ctx; + if (use_epoch == dtls1_use_previous_epoch) { + /* DTLS renegotiation is unsupported, so only epochs 0 (NULL cipher) and 1 + * (negotiated cipher) exist. */ + assert(ssl->d1->w_epoch == 1); + aead = NULL; + } + + return DTLS1_RT_HEADER_LENGTH + SSL_AEAD_CTX_explicit_nonce_len(aead); +} + int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, uint8_t type, const uint8_t *in, size_t in_len, enum dtls1_use_epoch_t use_epoch) { - if (buffers_alias(in, in_len, out, max_out)) { + const size_t prefix = dtls_seal_prefix_len(ssl, use_epoch); + if (buffers_alias(in, in_len, out, max_out) && + (max_out < prefix || out + prefix != in)) { OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT); return 0; }
diff --git a/ssl/internal.h b/ssl/internal.h index 068f95f..9557828 100644 --- a/ssl/internal.h +++ b/ssl/internal.h
@@ -307,11 +307,11 @@ /* SSL_AEAD_CTX_explicit_nonce_len returns the length of the explicit nonce for * |ctx|, if any. |ctx| may be NULL to denote the null cipher. */ -size_t SSL_AEAD_CTX_explicit_nonce_len(SSL_AEAD_CTX *ctx); +size_t SSL_AEAD_CTX_explicit_nonce_len(const SSL_AEAD_CTX *ctx); /* SSL_AEAD_CTX_max_overhead returns the maximum overhead of calling * |SSL_AEAD_CTX_seal|. |ctx| may be NULL to denote the null cipher. */ -size_t SSL_AEAD_CTX_max_overhead(SSL_AEAD_CTX *ctx); +size_t SSL_AEAD_CTX_max_overhead(const SSL_AEAD_CTX *ctx); /* SSL_AEAD_CTX_open authenticates and decrypts |in_len| bytes from |in| * in-place. On success, it sets |*out| to the plaintext in |in| and returns @@ -407,12 +407,11 @@ * use this to align buffers. * * Note when TLS 1.0 CBC record-splitting is enabled, this includes the one byte - * record and is the offset into second record's ciphertext. Thus this value may - * differ from |ssl_record_prefix_len| and sealing a small record may result in - * a smaller output than this value. + * record and is the offset into second record's ciphertext. Thus sealing a + * small record may result in a smaller output than this value. * - * TODO(davidben): Expose this as part of public API once the high-level - * buffer-free APIs are available. */ + * TODO(davidben): Is this alignment valuable? Record-splitting makes this a + * mess. */ size_t ssl_seal_align_prefix_len(const SSL *ssl); /* tls_seal_record seals a new record of type |type| and body |in| and writes it @@ -434,8 +433,14 @@ dtls1_use_current_epoch, }; +/* dtls_seal_prefix_len returns the number of bytes of prefix to reserve in + * front of the plaintext when sealing a record in-place. */ +size_t dtls_seal_prefix_len(const SSL *ssl, enum dtls1_use_epoch_t use_epoch); + /* dtls_seal_record implements |tls_seal_record| for DTLS. |use_epoch| selects - * which epoch's cipher state to use. */ + * which epoch's cipher state to use. Unlike |tls_seal_record|, |in| and |out| + * may alias but, if they do, |in| must be exactly |dtls_seal_prefix_len| bytes + * ahead of |out|. */ int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, uint8_t type, const uint8_t *in, size_t in_len, enum dtls1_use_epoch_t use_epoch);
diff --git a/ssl/ssl_aead_ctx.c b/ssl/ssl_aead_ctx.c index bba55ef..e18ba69 100644 --- a/ssl/ssl_aead_ctx.c +++ b/ssl/ssl_aead_ctx.c
@@ -126,7 +126,7 @@ OPENSSL_free(aead); } -size_t SSL_AEAD_CTX_explicit_nonce_len(SSL_AEAD_CTX *aead) { +size_t SSL_AEAD_CTX_explicit_nonce_len(const SSL_AEAD_CTX *aead) { #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) aead = NULL; #endif @@ -137,7 +137,7 @@ return 0; } -size_t SSL_AEAD_CTX_max_overhead(SSL_AEAD_CTX *aead) { +size_t SSL_AEAD_CTX_max_overhead(const SSL_AEAD_CTX *aead) { #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) aead = NULL; #endif