Home | History | Annotate | Line # | Download | only in ssl
      1 /*
      2  * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #include "ssl_local.h"
     11 #include "internal/ssl_unwrap.h"
     12 
     13 int ssl3_do_change_cipher_spec(SSL_CONNECTION *s)
     14 {
     15     int i;
     16     SSL *ssl = SSL_CONNECTION_GET_SSL(s);
     17 
     18     if (s->server)
     19         i = SSL3_CHANGE_CIPHER_SERVER_READ;
     20     else
     21         i = SSL3_CHANGE_CIPHER_CLIENT_READ;
     22 
     23     if (s->s3.tmp.key_block == NULL) {
     24         if (s->session == NULL || s->session->master_key_length == 0) {
     25             /* might happen if dtls1_read_bytes() calls this */
     26             ERR_raise(ERR_LIB_SSL, SSL_R_CCS_RECEIVED_EARLY);
     27             return 0;
     28         }
     29 
     30         s->session->cipher = s->s3.tmp.new_cipher;
     31         if (!ssl->method->ssl3_enc->setup_key_block(s)) {
     32             /* SSLfatal() already called */
     33             return 0;
     34         }
     35     }
     36 
     37     if (!ssl->method->ssl3_enc->change_cipher_state(s, i)) {
     38         /* SSLfatal() already called */
     39         return 0;
     40     }
     41 
     42     return 1;
     43 }
     44 
     45 int ssl3_send_alert(SSL_CONNECTION *s, int level, int desc)
     46 {
     47     SSL *ssl = SSL_CONNECTION_GET_SSL(s);
     48 
     49     /* Map tls/ssl alert value to correct one */
     50     if (SSL_CONNECTION_TREAT_AS_TLS13(s))
     51         desc = tls13_alert_code(desc);
     52     else
     53         desc = ssl->method->ssl3_enc->alert_value(desc);
     54     if (s->version == SSL3_VERSION && desc == SSL_AD_PROTOCOL_VERSION)
     55         desc = SSL_AD_HANDSHAKE_FAILURE; /* SSL 3.0 does not have
     56                                           * protocol_version alerts */
     57     if (desc < 0)
     58         return -1;
     59     if (s->shutdown & SSL_SENT_SHUTDOWN && desc != SSL_AD_CLOSE_NOTIFY)
     60         return -1;
     61     /* If a fatal one, remove from cache */
     62     if ((level == SSL3_AL_FATAL) && (s->session != NULL))
     63         SSL_CTX_remove_session(s->session_ctx, s->session);
     64 
     65     s->s3.alert_dispatch = SSL_ALERT_DISPATCH_PENDING;
     66     s->s3.send_alert[0] = level;
     67     s->s3.send_alert[1] = desc;
     68     if (!RECORD_LAYER_write_pending(&s->rlayer)) {
     69         /* data still being written out? */
     70         return ssl->method->ssl_dispatch_alert(ssl);
     71     }
     72     /*
     73      * else data is still being written out, we will get written some time in
     74      * the future
     75      */
     76     return -1;
     77 }
     78 
     79 int ssl3_dispatch_alert(SSL *s)
     80 {
     81     int i, j;
     82     void (*cb)(const SSL *ssl, int type, int val) = NULL;
     83     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
     84     OSSL_RECORD_TEMPLATE templ;
     85 
     86     if (sc == NULL)
     87         return -1;
     88 
     89     if (sc->rlayer.wrlmethod == NULL) {
     90         /* No write record layer so we can't sent and alert. We just ignore it */
     91         sc->s3.alert_dispatch = SSL_ALERT_DISPATCH_NONE;
     92         return 1;
     93     }
     94 
     95     templ.type = SSL3_RT_ALERT;
     96     templ.version = (sc->version == TLS1_3_VERSION) ? TLS1_2_VERSION
     97                                                     : sc->version;
     98     if (SSL_get_state(s) == TLS_ST_CW_CLNT_HELLO
     99         && !sc->renegotiate
    100         && TLS1_get_version(s) > TLS1_VERSION
    101         && sc->hello_retry_request == SSL_HRR_NONE) {
    102         templ.version = TLS1_VERSION;
    103     }
    104     templ.buf = &sc->s3.send_alert[0];
    105     templ.buflen = 2;
    106 
    107     if (RECORD_LAYER_write_pending(&sc->rlayer)) {
    108         if (sc->s3.alert_dispatch != SSL_ALERT_DISPATCH_RETRY) {
    109             /*
    110              * We have a write pending but it wasn't from a previous call to
    111              * this function! Can we ever get here? Maybe via API misuse??
    112              * Give up.
    113              */
    114             sc->s3.alert_dispatch = SSL_ALERT_DISPATCH_NONE;
    115             return -1;
    116         }
    117         /* Retry what we've already got pending */
    118         i = HANDLE_RLAYER_WRITE_RETURN(sc,
    119             sc->rlayer.wrlmethod->retry_write_records(sc->rlayer.wrl));
    120         if (i <= 0) {
    121             /* Could be NBIO. Keep alert_dispatch as SSL_ALERT_DISPATCH_RETRY */
    122             return -1;
    123         }
    124         sc->rlayer.wpend_tot = 0;
    125         sc->s3.alert_dispatch = SSL_ALERT_DISPATCH_NONE;
    126         return 1;
    127     }
    128 
    129     i = HANDLE_RLAYER_WRITE_RETURN(sc,
    130         sc->rlayer.wrlmethod->write_records(sc->rlayer.wrl, &templ, 1));
    131 
    132     if (i <= 0) {
    133         sc->s3.alert_dispatch = SSL_ALERT_DISPATCH_RETRY;
    134         sc->rlayer.wpend_tot = templ.buflen;
    135         sc->rlayer.wpend_type = templ.type;
    136         sc->rlayer.wpend_buf = templ.buf;
    137     } else {
    138         /*
    139          * Alert sent to BIO - now flush. If the message does not get sent due
    140          * to non-blocking IO, we will not worry too much.
    141          */
    142         (void)BIO_flush(sc->wbio);
    143         sc->s3.alert_dispatch = SSL_ALERT_DISPATCH_NONE;
    144 
    145         if (sc->msg_callback)
    146             sc->msg_callback(1, sc->version, SSL3_RT_ALERT, sc->s3.send_alert,
    147                 2, s, sc->msg_callback_arg);
    148 
    149         if (sc->info_callback != NULL)
    150             cb = sc->info_callback;
    151         else if (s->ctx->info_callback != NULL)
    152             cb = s->ctx->info_callback;
    153 
    154         if (cb != NULL) {
    155             j = (sc->s3.send_alert[0] << 8) | sc->s3.send_alert[1];
    156             cb(s, SSL_CB_WRITE_ALERT, j);
    157         }
    158     }
    159     return i;
    160 }
    161