unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk) { WPACKET pkt; if (!WPACKET_init(&pkt, s->init_buf)) { /* Should not happen */ SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN, ERR_R_INTERNAL_ERROR); goto err; } if (!ssl_set_handshake_header2(s, &pkt, SSL3_MT_CERTIFICATE) || !WPACKET_start_sub_packet_u24(&pkt)) { SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN, ERR_R_INTERNAL_ERROR); goto err; } if (!ssl_add_cert_chain(s, &pkt, cpk)) goto err; if (!WPACKET_close(&pkt) || !ssl_close_construct_packet(s, &pkt)) { SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN, ERR_R_INTERNAL_ERROR); goto err; } return 1; err: WPACKET_cleanup(&pkt); return 0; }
int tls_construct_finished(SSL *s, const char *sender, int slen) { int i; WPACKET pkt; if (!WPACKET_init(&pkt, s->init_buf) || !ssl_set_handshake_header2(s, &pkt, SSL3_MT_FINISHED)) { SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR); goto err; } i = s->method->ssl3_enc->final_finish_mac(s, sender, slen, s->s3->tmp.finish_md); if (i <= 0) { SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR); goto err; } s->s3->tmp.finish_md_len = i; if (!WPACKET_memcpy(&pkt, s->s3->tmp.finish_md, i)) { SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR); goto err; } /* * Copy the finished so we can use it for renegotiation checks */ if (!s->server) { OPENSSL_assert(i <= EVP_MAX_MD_SIZE); memcpy(s->s3->previous_client_finished, s->s3->tmp.finish_md, i); s->s3->previous_client_finished_len = i; } else { OPENSSL_assert(i <= EVP_MAX_MD_SIZE); memcpy(s->s3->previous_server_finished, s->s3->tmp.finish_md, i); s->s3->previous_server_finished_len = i; } if (!ssl_close_construct_packet(s, &pkt)) { SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR); goto err; } return 1; err: ossl_statem_set_error(s); WPACKET_cleanup(&pkt); ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return 0; }
/* * Given a |secret|; a |label| of length |labellen|; and a |hash| of the * handshake messages, derive a new secret |outlen| bytes long and store it in * the location pointed to be |out|. The |hash| value may be NULL. Returns 1 on * success 0 on failure. */ static int tls13_hkdf_expand(SSL *s, const unsigned char *secret, const unsigned char *label, size_t labellen, const unsigned char *hash, unsigned char *out, size_t outlen) { const unsigned char label_prefix[] = "TLS 1.3, "; const EVP_MD *md = ssl_handshake_md(s); EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); int ret; size_t hkdflabellen; size_t hashlen; /* * 2 bytes for length of whole HkdfLabel + 1 byte for length of combined * prefix and label + bytes for the label itself + bytes for the hash */ unsigned char hkdflabel[sizeof(uint16_t) + sizeof(uint8_t) + + sizeof(label_prefix) + TLS13_MAX_LABEL_LEN + EVP_MAX_MD_SIZE]; WPACKET pkt; if (pctx == NULL) return 0; hashlen = EVP_MD_size(md); if (!WPACKET_init_static_len(&pkt, hkdflabel, sizeof(hkdflabel), 0) || !WPACKET_put_bytes_u16(&pkt, outlen) || !WPACKET_start_sub_packet_u8(&pkt) || !WPACKET_memcpy(&pkt, label_prefix, sizeof(label_prefix) - 1) || !WPACKET_memcpy(&pkt, label, labellen) || !WPACKET_close(&pkt) || !WPACKET_sub_memcpy_u8(&pkt, hash, (hash == NULL) ? 0 : hashlen) || !WPACKET_get_total_written(&pkt, &hkdflabellen) || !WPACKET_finish(&pkt)) { WPACKET_cleanup(&pkt); return 0; } ret = EVP_PKEY_derive_init(pctx) <= 0 || EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) <= 0 || EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0 || EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, hashlen) <= 0 || EVP_PKEY_CTX_add1_hkdf_info(pctx, hkdflabel, hkdflabellen) <= 0 || EVP_PKEY_derive(pctx, out, &outlen) <= 0; EVP_PKEY_CTX_free(pctx); return ret == 0; }
int tls_construct_change_cipher_spec(SSL *s) { WPACKET pkt; if (!WPACKET_init(&pkt, s->init_buf) || !WPACKET_put_bytes_u8(&pkt, SSL3_MT_CCS) || !WPACKET_finish(&pkt)) { WPACKET_cleanup(&pkt); ossl_statem_set_error(s); SSLerr(SSL_F_TLS_CONSTRUCT_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR); ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return 0; } s->init_num = 1; s->init_off = 0; return 1; }
/* * Given a |secret|; a |label| of length |labellen|; and |data| of length * |datalen| (e.g. typically a hash of the handshake messages), derive a new * secret |outlen| bytes long and store it in the location pointed to be |out|. * The |data| value may be zero length. Any errors will be treated as fatal if * |fatal| is set. Returns 1 on success 0 on failure. */ int tls13_hkdf_expand(SSL *s, const EVP_MD *md, const unsigned char *secret, const unsigned char *label, size_t labellen, const unsigned char *data, size_t datalen, unsigned char *out, size_t outlen, int fatal) { static const unsigned char label_prefix[] = "tls13 "; EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); int ret; size_t hkdflabellen; size_t hashlen; /* * 2 bytes for length of derived secret + 1 byte for length of combined * prefix and label + bytes for the label itself + 1 byte length of hash * + bytes for the hash itself */ unsigned char hkdflabel[sizeof(uint16_t) + sizeof(uint8_t) + + sizeof(label_prefix) + TLS13_MAX_LABEL_LEN + 1 + EVP_MAX_MD_SIZE]; WPACKET pkt; if (pctx == NULL) return 0; if (labellen > TLS13_MAX_LABEL_LEN) { if (fatal) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_HKDF_EXPAND, ERR_R_INTERNAL_ERROR); } else { /* * Probably we have been called from SSL_export_keying_material(), * or SSL_export_keying_material_early(). */ SSLerr(SSL_F_TLS13_HKDF_EXPAND, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL); } EVP_PKEY_CTX_free(pctx); return 0; } hashlen = EVP_MD_size(md); if (!WPACKET_init_static_len(&pkt, hkdflabel, sizeof(hkdflabel), 0) || !WPACKET_put_bytes_u16(&pkt, outlen) || !WPACKET_start_sub_packet_u8(&pkt) || !WPACKET_memcpy(&pkt, label_prefix, sizeof(label_prefix) - 1) || !WPACKET_memcpy(&pkt, label, labellen) || !WPACKET_close(&pkt) || !WPACKET_sub_memcpy_u8(&pkt, data, (data == NULL) ? 0 : datalen) || !WPACKET_get_total_written(&pkt, &hkdflabellen) || !WPACKET_finish(&pkt)) { EVP_PKEY_CTX_free(pctx); WPACKET_cleanup(&pkt); if (fatal) SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_HKDF_EXPAND, ERR_R_INTERNAL_ERROR); else SSLerr(SSL_F_TLS13_HKDF_EXPAND, ERR_R_INTERNAL_ERROR); return 0; } ret = EVP_PKEY_derive_init(pctx) <= 0 || EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) <= 0 || EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0 || EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, hashlen) <= 0 || EVP_PKEY_CTX_add1_hkdf_info(pctx, hkdflabel, hkdflabellen) <= 0 || EVP_PKEY_derive(pctx, out, &outlen) <= 0; EVP_PKEY_CTX_free(pctx); if (ret != 0) { if (fatal) SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_HKDF_EXPAND, ERR_R_INTERNAL_ERROR); else SSLerr(SSL_F_TLS13_HKDF_EXPAND, ERR_R_INTERNAL_ERROR); } return ret == 0; }
int DTLSv1_listen(SSL *s, BIO_ADDR *client) { int next, n, ret = 0, clearpkt = 0; unsigned char cookie[DTLS1_COOKIE_LENGTH]; unsigned char seq[SEQ_NUM_SIZE]; const unsigned char *data; unsigned char *buf; size_t fragoff, fraglen, msglen; unsigned int rectype, versmajor, msgseq, msgtype, clientvers, cookielen; BIO *rbio, *wbio; BUF_MEM *bufm; BIO_ADDR *tmpclient = NULL; PACKET pkt, msgpkt, msgpayload, session, cookiepkt; /* Ensure there is no state left over from a previous invocation */ if (!SSL_clear(s)) return -1; ERR_clear_error(); rbio = SSL_get_rbio(s); wbio = SSL_get_wbio(s); if (!rbio || !wbio) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_BIO_NOT_SET); return -1; } /* * We only peek at incoming ClientHello's until we're sure we are going to * to respond with a HelloVerifyRequest. If its a ClientHello with a valid * cookie then we leave it in the BIO for accept to handle. */ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 1, NULL); /* * Note: This check deliberately excludes DTLS1_BAD_VER because that version * requires the MAC to be calculated *including* the first ClientHello * (without the cookie). Since DTLSv1_listen is stateless that cannot be * supported. DTLS1_BAD_VER must use cookies in a stateful manner (e.g. via * SSL_accept) */ if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNSUPPORTED_SSL_VERSION); return -1; } if (s->init_buf == NULL) { if ((bufm = BUF_MEM_new()) == NULL) { SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE); return -1; } if (!BUF_MEM_grow(bufm, SSL3_RT_MAX_PLAIN_LENGTH)) { BUF_MEM_free(bufm); SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE); return -1; } s->init_buf = bufm; } buf = (unsigned char *)s->init_buf->data; do { /* Get a packet */ clear_sys_error(); /* * Technically a ClientHello could be SSL3_RT_MAX_PLAIN_LENGTH * + DTLS1_RT_HEADER_LENGTH bytes long. Normally init_buf does not store * the record header as well, but we do here. We've set up init_buf to * be the standard size for simplicity. In practice we shouldn't ever * receive a ClientHello as long as this. If we do it will get dropped * in the record length check below. */ n = BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH); if (n <= 0) { if (BIO_should_retry(rbio)) { /* Non-blocking IO */ goto end; } return -1; } /* If we hit any problems we need to clear this packet from the BIO */ clearpkt = 1; if (!PACKET_buf_init(&pkt, buf, n)) { SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_INTERNAL_ERROR); return -1; } /* * Parse the received record. If there are any problems with it we just * dump it - with no alert. RFC6347 says this "Unlike TLS, DTLS is * resilient in the face of invalid records (e.g., invalid formatting, * length, MAC, etc.). In general, invalid records SHOULD be silently * discarded, thus preserving the association; however, an error MAY be * logged for diagnostic purposes." */ /* this packet contained a partial record, dump it */ if (n < DTLS1_RT_HEADER_LENGTH) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_RECORD_TOO_SMALL); goto end; } if (s->msg_callback) s->msg_callback(0, 0, SSL3_RT_HEADER, buf, DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg); /* Get the record header */ if (!PACKET_get_1(&pkt, &rectype) || !PACKET_get_1(&pkt, &versmajor)) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH); goto end; } if (rectype != SSL3_RT_HANDSHAKE) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE); goto end; } /* * Check record version number. We only check that the major version is * the same. */ if (versmajor != DTLS1_VERSION_MAJOR) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_BAD_PROTOCOL_VERSION_NUMBER); goto end; } if (!PACKET_forward(&pkt, 1) /* Save the sequence number: 64 bits, with top 2 bytes = epoch */ || !PACKET_copy_bytes(&pkt, seq, SEQ_NUM_SIZE) || !PACKET_get_length_prefixed_2(&pkt, &msgpkt)) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH); goto end; } /* * We allow data remaining at the end of the packet because there could * be a second record (but we ignore it) */ /* This is an initial ClientHello so the epoch has to be 0 */ if (seq[0] != 0 || seq[1] != 0) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE); goto end; } /* Get a pointer to the raw message for the later callback */ data = PACKET_data(&msgpkt); /* Finished processing the record header, now process the message */ if (!PACKET_get_1(&msgpkt, &msgtype) || !PACKET_get_net_3_len(&msgpkt, &msglen) || !PACKET_get_net_2(&msgpkt, &msgseq) || !PACKET_get_net_3_len(&msgpkt, &fragoff) || !PACKET_get_net_3_len(&msgpkt, &fraglen) || !PACKET_get_sub_packet(&msgpkt, &msgpayload, fraglen) || PACKET_remaining(&msgpkt) != 0) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH); goto end; } if (msgtype != SSL3_MT_CLIENT_HELLO) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE); goto end; } /* Message sequence number can only be 0 or 1 */ if (msgseq > 2) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_INVALID_SEQUENCE_NUMBER); goto end; } /* * We don't support fragment reassembly for ClientHellos whilst * listening because that would require server side state (which is * against the whole point of the ClientHello/HelloVerifyRequest * mechanism). Instead we only look at the first ClientHello fragment * and require that the cookie must be contained within it. */ if (fragoff != 0 || fraglen > msglen) { /* Non initial ClientHello fragment (or bad fragment) */ SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_FRAGMENTED_CLIENT_HELLO); goto end; } if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, data, fraglen + DTLS1_HM_HEADER_LENGTH, s, s->msg_callback_arg); if (!PACKET_get_net_2(&msgpayload, &clientvers)) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH); goto end; } /* * Verify client version is supported */ if (DTLS_VERSION_LT(clientvers, (unsigned int)s->method->version) && s->method->version != DTLS_ANY_VERSION) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_WRONG_VERSION_NUMBER); goto end; } if (!PACKET_forward(&msgpayload, SSL3_RANDOM_SIZE) || !PACKET_get_length_prefixed_1(&msgpayload, &session) || !PACKET_get_length_prefixed_1(&msgpayload, &cookiepkt)) { /* * Could be malformed or the cookie does not fit within the initial * ClientHello fragment. Either way we can't handle it. */ SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH); goto end; } /* * Check if we have a cookie or not. If not we need to send a * HelloVerifyRequest. */ if (PACKET_remaining(&cookiepkt) == 0) { next = LISTEN_SEND_VERIFY_REQUEST; } else { /* * We have a cookie, so lets check it. */ if (s->ctx->app_verify_cookie_cb == NULL) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_NO_VERIFY_COOKIE_CALLBACK); /* This is fatal */ return -1; } if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookiepkt), (unsigned int)PACKET_remaining(&cookiepkt)) == 0) { /* * We treat invalid cookies in the same was as no cookie as * per RFC6347 */ next = LISTEN_SEND_VERIFY_REQUEST; } else { /* Cookie verification succeeded */ next = LISTEN_SUCCESS; } } if (next == LISTEN_SEND_VERIFY_REQUEST) { WPACKET wpkt; unsigned int version; size_t wreclen; /* * There was no cookie in the ClientHello so we need to send a * HelloVerifyRequest. If this fails we do not worry about trying * to resend, we just drop it. */ /* * Dump the read packet, we don't need it any more. Ignore return * value */ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL); BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH); BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 1, NULL); /* Generate the cookie */ if (s->ctx->app_gen_cookie_cb == NULL || s->ctx->app_gen_cookie_cb(s, cookie, &cookielen) == 0 || cookielen > 255) { SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_COOKIE_GEN_CALLBACK_FAILURE); /* This is fatal */ return -1; } /* * Special case: for hello verify request, client version 1.0 and we * haven't decided which version to use yet send back using version * 1.0 header: otherwise some clients will ignore it. */ version = (s->method->version == DTLS_ANY_VERSION) ? DTLS1_VERSION : s->version; /* Construct the record and message headers */ if (!WPACKET_init(&wpkt, s->init_buf) || !WPACKET_put_bytes_u8(&wpkt, SSL3_RT_HANDSHAKE) || !WPACKET_put_bytes_u16(&wpkt, version) /* * Record sequence number is always the same as in the * received ClientHello */ || !WPACKET_memcpy(&wpkt, seq, SEQ_NUM_SIZE) /* End of record, start sub packet for message */ || !WPACKET_start_sub_packet_u16(&wpkt) /* Message type */ || !WPACKET_put_bytes_u8(&wpkt, DTLS1_MT_HELLO_VERIFY_REQUEST) /* * Message length - doesn't follow normal TLS convention: * the length isn't the last thing in the message header. * We'll need to fill this in later when we know the * length. Set it to zero for now */ || !WPACKET_put_bytes_u24(&wpkt, 0) /* * Message sequence number is always 0 for a * HelloVerifyRequest */ || !WPACKET_put_bytes_u16(&wpkt, 0) /* * We never fragment a HelloVerifyRequest, so fragment * offset is 0 */ || !WPACKET_put_bytes_u24(&wpkt, 0) /* * Fragment length is the same as message length, but * this *is* the last thing in the message header so we * can just start a sub-packet. No need to come back * later for this one. */ || !WPACKET_start_sub_packet_u24(&wpkt) /* Create the actual HelloVerifyRequest body */ || !dtls_raw_hello_verify_request(&wpkt, cookie, cookielen) /* Close message body */ || !WPACKET_close(&wpkt) /* Close record body */ || !WPACKET_close(&wpkt) || !WPACKET_get_total_written(&wpkt, &wreclen) || !WPACKET_finish(&wpkt)) { SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_INTERNAL_ERROR); WPACKET_cleanup(&wpkt); /* This is fatal */ return -1; } /* * Fix up the message len in the message header. Its the same as the * fragment len which has been filled in by WPACKET, so just copy * that. Destination for the message len is after the record header * plus one byte for the message content type. The source is the * last 3 bytes of the message header */ memcpy(&buf[DTLS1_RT_HEADER_LENGTH + 1], &buf[DTLS1_RT_HEADER_LENGTH + DTLS1_HM_HEADER_LENGTH - 3], 3); if (s->msg_callback) s->msg_callback(1, 0, SSL3_RT_HEADER, buf, DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg); if ((tmpclient = BIO_ADDR_new()) == NULL) { SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE); goto end; } /* * This is unnecessary if rbio and wbio are one and the same - but * maybe they're not. We ignore errors here - some BIOs do not * support this. */ if (BIO_dgram_get_peer(rbio, tmpclient) > 0) { (void)BIO_dgram_set_peer(wbio, tmpclient); } BIO_ADDR_free(tmpclient); tmpclient = NULL; /* TODO(size_t): convert this call */ if (BIO_write(wbio, buf, wreclen) < (int)wreclen) { if (BIO_should_retry(wbio)) { /* * Non-blocking IO...but we're stateless, so we're just * going to drop this packet. */ goto end; } return -1; } if (BIO_flush(wbio) <= 0) { if (BIO_should_retry(wbio)) { /* * Non-blocking IO...but we're stateless, so we're just * going to drop this packet. */ goto end; } return -1; } } } while (next != LISTEN_SUCCESS); /* * Set expected sequence numbers to continue the handshake. */ s->d1->handshake_read_seq = 1; s->d1->handshake_write_seq = 1; s->d1->next_handshake_write_seq = 1; DTLS_RECORD_LAYER_set_write_sequence(&s->rlayer, seq); /* * We are doing cookie exchange, so make sure we set that option in the * SSL object */ SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE); /* * Tell the state machine that we've done the initial hello verify * exchange */ ossl_statem_set_hello_verify_done(s); /* * Some BIOs may not support this. If we fail we clear the client address */ if (BIO_dgram_get_peer(rbio, client) <= 0) BIO_ADDR_clear(client); ret = 1; clearpkt = 0; end: BIO_ADDR_free(tmpclient); BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL); if (clearpkt) { /* Dump this packet. Ignore return value */ BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH); } return ret; }
/*- * tls13_enc encrypts/decrypts |n_recs| in |recs|. Will call SSLfatal() for * internal errors, but not otherwise. * * Returns: * 0: (in non-constant time) if the record is publically invalid (i.e. too * short etc). * 1: if the record encryption was successful. * -1: if the record's AEAD-authenticator is invalid or, if sending, * an internal error occurred. */ int tls13_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int sending) { EVP_CIPHER_CTX *ctx; unsigned char iv[EVP_MAX_IV_LENGTH], recheader[SSL3_RT_HEADER_LENGTH]; size_t ivlen, taglen, offset, loop, hdrlen; unsigned char *staticiv; unsigned char *seq; int lenu, lenf; SSL3_RECORD *rec = &recs[0]; uint32_t alg_enc; WPACKET wpkt; if (n_recs != 1) { /* Should not happen */ /* TODO(TLS1.3): Support pipelining */ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC, ERR_R_INTERNAL_ERROR); return -1; } if (sending) { ctx = s->enc_write_ctx; staticiv = s->write_iv; seq = RECORD_LAYER_get_write_sequence(&s->rlayer); } else { ctx = s->enc_read_ctx; staticiv = s->read_iv; seq = RECORD_LAYER_get_read_sequence(&s->rlayer); } /* * 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_iv_length(ctx); if (s->early_data_state == SSL_EARLY_DATA_WRITING || s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) { if (s->session != NULL && s->session->ext.max_early_data > 0) { alg_enc = s->session->cipher->algorithm_enc; } else { if (!ossl_assert(s->psksession != NULL && s->psksession->ext.max_early_data > 0)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC, ERR_R_INTERNAL_ERROR); return -1; } alg_enc = s->psksession->cipher->algorithm_enc; } } else { /* * To get here we must have selected a ciphersuite - otherwise ctx would * be NULL */ if (!ossl_assert(s->s3->tmp.new_cipher != NULL)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC, ERR_R_INTERNAL_ERROR); return -1; } alg_enc = s->s3->tmp.new_cipher->algorithm_enc; } if (alg_enc & SSL_AESCCM) { if (alg_enc & (SSL_AES128CCM8 | SSL_AES256CCM8)) taglen = EVP_CCM8_TLS_TAG_LEN; else taglen = EVP_CCM_TLS_TAG_LEN; if (sending && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, taglen, NULL) <= 0) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC, ERR_R_INTERNAL_ERROR); return -1; } } else if (alg_enc & SSL_AESGCM) { taglen = EVP_GCM_TLS_TAG_LEN; } else if (alg_enc & SSL_CHACHA20) { taglen = EVP_CHACHAPOLY_TLS_TAG_LEN; } else { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC, ERR_R_INTERNAL_ERROR); return -1; } if (!sending) { /* * Take off tag. There must be at least one byte of content type as * well as the tag */ if (rec->length < taglen + 1) return 0; rec->length -= taglen; } /* Set up IV */ if (ivlen < SEQ_NUM_SIZE) { /* Should not happen */ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC, ERR_R_INTERNAL_ERROR); return -1; } 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 -1; } /* TODO(size_t): lenu/lenf should be a size_t but EVP doesn't support it */ if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv, sending) <= 0 || (!sending && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, taglen, rec->data + rec->length) <= 0)) { return -1; } /* 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 + taglen) || !WPACKET_get_total_written(&wpkt, &hdrlen) || hdrlen != SSL3_RT_HEADER_LENGTH || !WPACKET_finish(&wpkt)) { WPACKET_cleanup(&wpkt); return -1; } /* * For CCM we must explicitly set the total plaintext length before we add * any AAD. */ if (((alg_enc & SSL_AESCCM) != 0 && 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 -1; } if (sending) { /* Add the tag */ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, taglen, rec->data + rec->length) <= 0) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC, ERR_R_INTERNAL_ERROR); return -1; } rec->length += taglen; } return 1; }