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