+
+/* Replace ClientHello1 in the transcript hash with a synthetic message */
+int create_synthetic_message_hash(SSL *s, const unsigned char *hashval,
+ size_t hashlen, const unsigned char *hrr,
+ size_t hrrlen)
+{
+ unsigned char hashvaltmp[EVP_MAX_MD_SIZE];
+ unsigned char msghdr[SSL3_HM_HEADER_LENGTH];
+
+ memset(msghdr, 0, sizeof(msghdr));
+
+ if (hashval == NULL) {
+ hashval = hashvaltmp;
+ hashlen = 0;
+ /* Get the hash of the initial ClientHello */
+ if (!ssl3_digest_cached_records(s, 0)
+ || !ssl_handshake_hash(s, hashvaltmp, sizeof(hashvaltmp),
+ &hashlen)) {
+ /* SSLfatal() already called */
+ return 0;
+ }
+ }
+
+ /* Reinitialise the transcript hash */
+ if (!ssl3_init_finished_mac(s)) {
+ /* SSLfatal() already called */
+ return 0;
+ }
+
+ /* Inject the synthetic message_hash message */
+ msghdr[0] = SSL3_MT_MESSAGE_HASH;
+ msghdr[SSL3_HM_HEADER_LENGTH - 1] = (unsigned char)hashlen;
+ if (!ssl3_finish_mac(s, msghdr, SSL3_HM_HEADER_LENGTH)
+ || !ssl3_finish_mac(s, hashval, hashlen)) {
+ /* SSLfatal() already called */
+ return 0;
+ }
+
+ /*
+ * Now re-inject the HRR and current message if appropriate (we just deleted
+ * it when we reinitialised the transcript hash above). Only necessary after
+ * receiving a ClientHello2 with a cookie.
+ */
+ if (hrr != NULL
+ && (!ssl3_finish_mac(s, hrr, hrrlen)
+ || !ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
+ s->s3->tmp.message_size
+ + SSL3_HM_HEADER_LENGTH))) {
+ /* SSLfatal() already called */
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b)
+{
+ return X509_NAME_cmp(*a, *b);
+}
+
+int parse_ca_names(SSL *s, PACKET *pkt)
+{
+ STACK_OF(X509_NAME) *ca_sk = sk_X509_NAME_new(ca_dn_cmp);
+ X509_NAME *xn = NULL;
+ PACKET cadns;
+
+ if (ca_sk == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_PARSE_CA_NAMES,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ /* get the CA RDNs */
+ if (!PACKET_get_length_prefixed_2(pkt, &cadns)) {
+ SSLfatal(s, SSL_AD_DECODE_ERROR,SSL_F_PARSE_CA_NAMES,
+ SSL_R_LENGTH_MISMATCH);
+ goto err;
+ }
+
+ while (PACKET_remaining(&cadns)) {
+ const unsigned char *namestart, *namebytes;
+ unsigned int name_len;
+
+ if (!PACKET_get_net_2(&cadns, &name_len)
+ || !PACKET_get_bytes(&cadns, &namebytes, name_len)) {
+ SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_PARSE_CA_NAMES,
+ SSL_R_LENGTH_MISMATCH);
+ goto err;
+ }
+
+ namestart = namebytes;
+ if ((xn = d2i_X509_NAME(NULL, &namebytes, name_len)) == NULL) {
+ SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_PARSE_CA_NAMES,
+ ERR_R_ASN1_LIB);
+ goto err;
+ }
+ if (namebytes != (namestart + name_len)) {
+ SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_PARSE_CA_NAMES,
+ SSL_R_CA_DN_LENGTH_MISMATCH);
+ goto err;
+ }
+
+ if (!sk_X509_NAME_push(ca_sk, xn)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_PARSE_CA_NAMES,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ xn = NULL;
+ }
+
+ sk_X509_NAME_pop_free(s->s3->tmp.peer_ca_names, X509_NAME_free);
+ s->s3->tmp.peer_ca_names = ca_sk;
+
+ return 1;
+
+ err:
+ sk_X509_NAME_pop_free(ca_sk, X509_NAME_free);
+ X509_NAME_free(xn);
+ return 0;
+}
+
+const STACK_OF(X509_NAME) *get_ca_names(SSL *s)
+{
+ const STACK_OF(X509_NAME) *ca_sk = NULL;;
+
+ if (s->server) {
+ ca_sk = SSL_get_client_CA_list(s);
+ if (ca_sk != NULL && sk_X509_NAME_num(ca_sk) == 0)
+ ca_sk = NULL;
+ }
+
+ if (ca_sk == NULL)
+ ca_sk = SSL_get0_CA_list(s);
+
+ return ca_sk;
+}
+
+int construct_ca_names(SSL *s, const STACK_OF(X509_NAME) *ca_sk, WPACKET *pkt)
+{
+ /* Start sub-packet for client CA list */
+ if (!WPACKET_start_sub_packet_u16(pkt)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_CA_NAMES,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ if (ca_sk != NULL) {
+ int i;
+
+ for (i = 0; i < sk_X509_NAME_num(ca_sk); i++) {
+ unsigned char *namebytes;
+ X509_NAME *name = sk_X509_NAME_value(ca_sk, i);
+ int namelen;
+
+ if (name == NULL
+ || (namelen = i2d_X509_NAME(name, NULL)) < 0
+ || !WPACKET_sub_allocate_bytes_u16(pkt, namelen,
+ &namebytes)
+ || i2d_X509_NAME(name, &namebytes) != namelen) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_CA_NAMES,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ }
+ }
+
+ if (!WPACKET_close(pkt)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_CA_NAMES,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Create a buffer containing data to be signed for server key exchange */
+size_t construct_key_exchange_tbs(SSL *s, unsigned char **ptbs,
+ const void *param, size_t paramlen)
+{
+ size_t tbslen = 2 * SSL3_RANDOM_SIZE + paramlen;
+ unsigned char *tbs = OPENSSL_malloc(tbslen);
+
+ if (tbs == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_KEY_EXCHANGE_TBS,
+ ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ memcpy(tbs, s->s3->client_random, SSL3_RANDOM_SIZE);
+ memcpy(tbs + SSL3_RANDOM_SIZE, s->s3->server_random, SSL3_RANDOM_SIZE);
+
+ memcpy(tbs + SSL3_RANDOM_SIZE * 2, param, paramlen);
+
+ *ptbs = tbs;
+ return tbslen;
+}
+
+/*
+ * Saves the current handshake digest for Post-Handshake Auth,
+ * Done after ClientFinished is processed, done exactly once
+ */
+int tls13_save_handshake_digest_for_pha(SSL *s)
+{
+ if (s->pha_dgst == NULL) {
+ if (!ssl3_digest_cached_records(s, 1))
+ /* SSLfatal() already called */
+ return 0;
+
+ s->pha_dgst = EVP_MD_CTX_new();
+ if (s->pha_dgst == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS13_SAVE_HANDSHAKE_DIGEST_FOR_PHA,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ if (!EVP_MD_CTX_copy_ex(s->pha_dgst,
+ s->s3->handshake_dgst)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS13_SAVE_HANDSHAKE_DIGEST_FOR_PHA,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * Restores the Post-Handshake Auth handshake digest
+ * Done just before sending/processing the Cert Request
+ */
+int tls13_restore_handshake_digest_for_pha(SSL *s)
+{
+ if (s->pha_dgst == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS13_RESTORE_HANDSHAKE_DIGEST_FOR_PHA,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ if (!EVP_MD_CTX_copy_ex(s->s3->handshake_dgst,
+ s->pha_dgst)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS13_RESTORE_HANDSHAKE_DIGEST_FOR_PHA,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ return 1;
+}