Ensure various SSL options are passed down to the record layer
[openssl.git] / ssl / record / methods / tlsrecord.c
index 1646ba5ba1811832f9d4062f666365eb2845fe0f..d12b38ce3947a16a672fd45a265238c167b24501 100644 (file)
@@ -104,6 +104,11 @@ struct ossl_record_layer_st
     /* Only used by SSLv3 */
     unsigned char mac_secret[EVP_MAX_MD_SIZE];
 
+    /* TLSv1.3 static IV */
+    unsigned char iv[EVP_MAX_IV_LENGTH];
+
+    size_t taglen;
+
     /* Function pointers for version specific functions */
     /* Function pointers for version specific functions */
     struct record_functions_st *funcs;
@@ -169,23 +174,6 @@ static int tls_provider_set_tls_parameters(OSSL_RECORD_LAYER *rl,
     return 1;
 }
 
-static int tls_fail_set_crypto_state(OSSL_RECORD_LAYER *rl, int level,
-                                     unsigned char *key, size_t keylen,
-                                     unsigned char *iv, size_t ivlen,
-                                     unsigned char *mackey, size_t mackeylen,
-                                     const EVP_CIPHER *ciph,
-                                     size_t taglen,
-                                     /* TODO(RECLAYER): This probably should not be an int */
-                                     int mactype,
-                                     const EVP_MD *md,
-                                     const SSL_COMP *comp,
-                                     /* TODO(RECLAYER): Remove me */
-                                     SSL_CONNECTION *s)
-{
-    RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-    return 0;
-}
-
 static int tls_any_set_crypto_state(OSSL_RECORD_LAYER *rl, int level,
                                     unsigned char *key, size_t keylen,
                                     unsigned char *iv, size_t ivlen,
@@ -410,6 +398,51 @@ static int tls1_set_crypto_state(OSSL_RECORD_LAYER *rl, int level,
     return 1;
 }
 
+static int tls13_set_crypto_state(OSSL_RECORD_LAYER *rl, int level,
+                                  unsigned char *key, size_t keylen,
+                                  unsigned char *iv, size_t ivlen,
+                                  unsigned char *mackey, size_t mackeylen,
+                                  const EVP_CIPHER *ciph,
+                                  size_t taglen,
+                                  /* TODO(RECLAYER): This probably should not be an int */
+                                  int mactype,
+                                  const EVP_MD *md,
+                                  const SSL_COMP *comp,
+                                  /* TODO(RECLAYER): Remove me */
+                                  SSL_CONNECTION *s)
+{
+    EVP_CIPHER_CTX *ciph_ctx;
+    int mode;
+
+    if (ivlen > sizeof(rl->iv)) {
+        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    memcpy(rl->iv, iv, ivlen);
+
+    ciph_ctx = rl->enc_read_ctx = EVP_CIPHER_CTX_new();
+    if (ciph_ctx == NULL) {
+        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    RECORD_LAYER_reset_read_sequence(&s->rlayer);
+    rl->taglen = taglen;
+
+    mode = EVP_CIPHER_get_mode(ciph);
+
+    if (EVP_DecryptInit_ex(ciph_ctx, ciph, NULL, NULL, NULL) <= 0
+        || !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_IVLEN, ivlen, NULL)
+        || (mode == EVP_CIPH_CCM_MODE
+            && !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_TAG,  taglen, NULL))
+        || EVP_DecryptInit_ex(ciph_ctx, NULL, NULL, key, NULL) <= 0) {
+        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
+        return 0;
+    }
+
+    return 1;
+}
+
 static int tls_any_cipher(OSSL_RECORD_LAYER *rl, SSL3_RECORD *recs, size_t n_recs,
                           int sending, SSL_MAC_BUF *macs, size_t macsize,
                           /* TODO(RECLAYER): Remove me */ SSL_CONNECTION *s)
@@ -875,6 +908,139 @@ static int tls1_cipher(OSSL_RECORD_LAYER *rl, SSL3_RECORD *recs, size_t n_recs,
     return 1;
 }
 
+static int tls13_cipher(OSSL_RECORD_LAYER *rl, SSL3_RECORD *recs, size_t n_recs,
+                        int sending, SSL_MAC_BUF *mac, size_t macsize,
+                        /* TODO(RECLAYER): Remove me */ SSL_CONNECTION *s)
+{
+    EVP_CIPHER_CTX *ctx;
+    unsigned char iv[EVP_MAX_IV_LENGTH], recheader[SSL3_RT_HEADER_LENGTH];
+    size_t ivlen, offset, loop, hdrlen;
+    unsigned char *staticiv;
+    unsigned char *seq;
+    int lenu, lenf;
+    SSL3_RECORD *rec = &recs[0];
+    WPACKET wpkt;
+    const EVP_CIPHER *cipher;
+    int mode;
+
+    if (n_recs != 1) {
+        /* Should not happen */
+        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (sending) {
+        ctx = s->enc_write_ctx;
+        staticiv = s->write_iv;
+        seq = RECORD_LAYER_get_write_sequence(&s->rlayer);
+    } else {
+        ctx = rl->enc_read_ctx;
+        staticiv = rl->iv;
+        seq = RECORD_LAYER_get_read_sequence(&s->rlayer);
+    }
+
+    cipher = EVP_CIPHER_CTX_get0_cipher(ctx);
+    if (cipher == NULL) {
+        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    mode = EVP_CIPHER_get_mode(cipher);
+
+    /*
+     * If we're sending an alert and ctx != NULL then we must be forcing
+     * plaintext alerts. If we're reading and ctx != NULL then we allow
+     * plaintext alerts at certain points in the handshake. If we've got this
+     * far then we have already validated that a plaintext alert is ok here.
+     */
+    if (ctx == NULL || rec->type == SSL3_RT_ALERT) {
+        memmove(rec->data, rec->input, rec->length);
+        rec->input = rec->data;
+        return 1;
+    }
+
+    ivlen = EVP_CIPHER_CTX_get_iv_length(ctx);
+
+    if (!sending) {
+        /*
+         * Take off tag. There must be at least one byte of content type as
+         * well as the tag
+         */
+        if (rec->length < rl->taglen + 1)
+            return 0;
+        rec->length -= rl->taglen;
+    }
+
+    /* Set up IV */
+    if (ivlen < SEQ_NUM_SIZE) {
+        /* Should not happen */
+        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    offset = ivlen - SEQ_NUM_SIZE;
+    memcpy(iv, staticiv, offset);
+    for (loop = 0; loop < SEQ_NUM_SIZE; loop++)
+        iv[offset + loop] = staticiv[offset + loop] ^ seq[loop];
+
+    /* Increment the sequence counter */
+    for (loop = SEQ_NUM_SIZE; loop > 0; loop--) {
+        ++seq[loop - 1];
+        if (seq[loop - 1] != 0)
+            break;
+    }
+    if (loop == 0) {
+        /* Sequence has wrapped */
+        return 0;
+    }
+
+    if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv, sending) <= 0
+            || (!sending && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
+                                                rl->taglen,
+                                                rec->data + rec->length) <= 0)) {
+        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /* Set up the AAD */
+    if (!WPACKET_init_static_len(&wpkt, recheader, sizeof(recheader), 0)
+            || !WPACKET_put_bytes_u8(&wpkt, rec->type)
+            || !WPACKET_put_bytes_u16(&wpkt, rec->rec_version)
+            || !WPACKET_put_bytes_u16(&wpkt, rec->length + rl->taglen)
+            || !WPACKET_get_total_written(&wpkt, &hdrlen)
+            || hdrlen != SSL3_RT_HEADER_LENGTH
+            || !WPACKET_finish(&wpkt)) {
+        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        WPACKET_cleanup(&wpkt);
+        return 0;
+    }
+
+    /*
+     * For CCM we must explicitly set the total plaintext length before we add
+     * any AAD.
+     */
+    if ((mode == EVP_CIPH_CCM_MODE
+                 && EVP_CipherUpdate(ctx, NULL, &lenu, NULL,
+                                     (unsigned int)rec->length) <= 0)
+            || EVP_CipherUpdate(ctx, NULL, &lenu, recheader,
+                                sizeof(recheader)) <= 0
+            || EVP_CipherUpdate(ctx, rec->data, &lenu, rec->input,
+                                (unsigned int)rec->length) <= 0
+            || EVP_CipherFinal_ex(ctx, rec->data + lenu, &lenf) <= 0
+            || (size_t)(lenu + lenf) != rec->length) {
+        return 0;
+    }
+    if (sending) {
+        /* Add the tag */
+        if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, rl->taglen,
+                                rec->data + rec->length) <= 0) {
+            RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        rec->length += rl->taglen;
+    }
+
+    return 1;
+}
+
 static const unsigned char ssl3_pad_1[48] = {
     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
@@ -1102,7 +1268,6 @@ static int tls1_mac(OSSL_RECORD_LAYER *rl, SSL3_RECORD *rec, unsigned char *md,
     return ret;
 }
 
-
 struct record_functions_st tls_any_funcs = {
     tls_any_set_crypto_state,
     tls_any_cipher,
@@ -1110,8 +1275,8 @@ struct record_functions_st tls_any_funcs = {
 };
 
 struct record_functions_st tls_1_3_funcs = {
-    tls_fail_set_crypto_state,
-    NULL,
+    tls13_set_crypto_state,
+    tls13_cipher,
     NULL
 };
 
@@ -1321,7 +1486,7 @@ static int tls_read_n(OSSL_RECORD_LAYER *rl, size_t n, size_t max, int extend,
      * Ktls always reads full records.
      * Also, we always act like read_ahead is set for DTLS.
      */
-    if (!BIO_get_ktls_recv(s->rbio) && !rl->read_ahead
+    if (!BIO_get_ktls_recv(rl->bio) && !rl->read_ahead
             && !rl->isdtls) {
         /* ignore max parameter */
         max = n;
@@ -1648,7 +1813,7 @@ static int tls_get_more_records(OSSL_RECORD_LAYER *rl,
                 }
 
                 if (SSL_CONNECTION_IS_TLS13(s)
-                        && s->enc_read_ctx != NULL
+                        && rl->enc_read_ctx != NULL
                         && !using_ktls) {
                     if (thisrr->type != SSL3_RT_APPLICATION_DATA
                             && (thisrr->type != SSL3_RT_CHANGE_CIPHER_SPEC
@@ -1866,10 +2031,7 @@ static int tls_get_more_records(OSSL_RECORD_LAYER *rl,
      * TODO(RECLAYER): Only call rl functions once TLSv1.3/SSLv3 is moved to new
      * record layer code
      */
-    if (!SSL_CONNECTION_IS_TLS13(s))
-        enc_err = rl->funcs->cipher(rl, rr, num_recs, 0, macbufs, mac_size, s);
-    else
-        enc_err = ssl->method->ssl3_enc->enc(s, rr, num_recs, 0, macbufs, mac_size);
+    enc_err = rl->funcs->cipher(rl, rr, num_recs, 0, macbufs, mac_size, s);
 
     /*-
      * enc_err is:
@@ -1970,7 +2132,7 @@ static int tls_get_more_records(OSSL_RECORD_LAYER *rl,
         }
 
         if (SSL_CONNECTION_IS_TLS13(s)
-                && s->enc_read_ctx != NULL
+                && rl->enc_read_ctx != NULL
                 && thisrr->type != SSL3_RT_ALERT) {
             /*
              * The following logic are irrelevant in KTLS: the kernel provides
@@ -2179,6 +2341,10 @@ static OSSL_RECORD_LAYER *tls_new_record_layer(OSSL_LIB_CTX *libctx,
         goto err;
     }
 
+    /*
+     * TODO(RECLAYER): Need to handle the case where the params are updated
+     * after the record layer has been created.
+     */
     p = OSSL_PARAM_locate_const(options, OSSL_LIBSSL_RECORD_LAYER_PARAM_OPTIONS);
     if (p != NULL && !OSSL_PARAM_get_uint64(p, &rl->options)) {
         RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER);
@@ -2191,11 +2357,22 @@ static OSSL_RECORD_LAYER *tls_new_record_layer(OSSL_LIB_CTX *libctx,
         goto err;
     }
 
-
-    p = OSSL_PARAM_locate_const(options, OSSL_LIBSSL_RECORD_LAYER_PARAM_READ_AHEAD);
-    if (p != NULL && !OSSL_PARAM_get_int(p, &rl->read_ahead)) {
-        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER);
-        goto err;
+    if (level == OSSL_RECORD_PROTECTION_LEVEL_APPLICATION) {
+        /*
+         * We ignore any read_ahead setting prior to the application protection
+         * level. Otherwise we may read ahead data in a lower protection level
+         * that is destined for a higher protection level. To simplify the logic
+         * we don't support that at this stage.
+         */
+        /*
+         * TODO(RECLAYER): Handle the case of read_ahead at the application
+         * level and a key update/reneg occurs.
+         */
+        p = OSSL_PARAM_locate_const(options, OSSL_LIBSSL_RECORD_LAYER_PARAM_READ_AHEAD);
+        if (p != NULL && !OSSL_PARAM_get_int(p, &rl->read_ahead)) {
+            RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER);
+            goto err;
+        }
     }
 
     rl->libctx = libctx;
@@ -2288,6 +2465,7 @@ static OSSL_RECORD_LAYER *dtls_new_record_layer(OSSL_LIB_CTX *libctx,
 
 static void tls_free(OSSL_RECORD_LAYER *rl)
 {
+    /* TODO(RECLAYER): Cleanse sensitive fields */
     BIO_free(rl->bio);
     OPENSSL_free(rl);
 }