int ssl_add_cert_chain(SSL *ssl, CBB *cbb) { if (!ssl_has_certificate(ssl)) { return CBB_add_u24(cbb, 0); } CBB certs; if (!CBB_add_u24_length_prefixed(cbb, &certs)) { goto err; } STACK_OF(CRYPTO_BUFFER) *chain = ssl->cert->chain; for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(chain); i++) { CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(chain, i); CBB child; if (!CBB_add_u24_length_prefixed(&certs, &child) || !CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer), CRYPTO_BUFFER_len(buffer)) || !CBB_flush(&certs)) { goto err; } } return CBB_flush(cbb); err: OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; }
static int test_cbb_prefixed(void) { static const uint8_t kExpected[] = {0, 1, 1, 0, 2, 2, 3, 0, 0, 3, 4, 5, 6, 5, 4, 1, 0, 1, 2}; uint8_t *buf; size_t buf_len; CBB cbb, contents, inner_contents, inner_inner_contents; int ok; if (!CBB_init(&cbb, 0) || !CBB_add_u8_length_prefixed(&cbb, &contents) || !CBB_add_u8_length_prefixed(&cbb, &contents) || !CBB_add_u8(&contents, 1) || !CBB_add_u16_length_prefixed(&cbb, &contents) || !CBB_add_u16(&contents, 0x203) || !CBB_add_u24_length_prefixed(&cbb, &contents) || !CBB_add_u24(&contents, 0x40506) || !CBB_add_u8_length_prefixed(&cbb, &contents) || !CBB_add_u8_length_prefixed(&contents, &inner_contents) || !CBB_add_u8(&inner_contents, 1) || !CBB_add_u16_length_prefixed(&inner_contents, &inner_inner_contents) || !CBB_add_u8(&inner_inner_contents, 2) || !CBB_finish(&cbb, &buf, &buf_len)) { return 0; } ok = buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) == 0; free(buf); return ok; }
int tls13_prepare_certificate(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; CBB cbb, body, certificate_list; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE) || /* The request context is always empty in the handshake. */ !CBB_add_u8(&body, 0) || !CBB_add_u24_length_prefixed(&body, &certificate_list)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); goto err; } if (!ssl_has_certificate(ssl)) { if (!ssl_complete_message(ssl, &cbb)) { goto err; } return 1; } CERT *cert = ssl->cert; CBB leaf, extensions; if (!CBB_add_u24_length_prefixed(&certificate_list, &leaf) || !ssl_add_cert_to_cbb(&leaf, cert->x509_leaf) || !CBB_add_u16_length_prefixed(&certificate_list, &extensions)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); goto err; } if (hs->scts_requested && ssl->ctx->signed_cert_timestamp_list_length != 0) { CBB contents; if (!CBB_add_u16(&extensions, TLSEXT_TYPE_certificate_timestamp) || !CBB_add_u16_length_prefixed(&extensions, &contents) || !CBB_add_bytes(&contents, ssl->ctx->signed_cert_timestamp_list, ssl->ctx->signed_cert_timestamp_list_length) || !CBB_flush(&extensions)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); goto err; } } if (hs->ocsp_stapling_requested && ssl->ocsp_response != NULL) { CBB contents, ocsp_response; if (!CBB_add_u16(&extensions, TLSEXT_TYPE_status_request) || !CBB_add_u16_length_prefixed(&extensions, &contents) || !CBB_add_u8(&contents, TLSEXT_STATUSTYPE_ocsp) || !CBB_add_u24_length_prefixed(&contents, &ocsp_response) || !CBB_add_bytes(&ocsp_response, CRYPTO_BUFFER_data(ssl->ocsp_response), CRYPTO_BUFFER_len(ssl->ocsp_response)) || !CBB_flush(&extensions)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); goto err; } } for (size_t i = 0; i < sk_X509_num(cert->x509_chain); i++) { CBB child; if (!CBB_add_u24_length_prefixed(&certificate_list, &child) || !ssl_add_cert_to_cbb(&child, sk_X509_value(cert->x509_chain, i)) || !CBB_add_u16(&certificate_list, 0 /* no extensions */)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); goto err; } } if (!ssl_complete_message(ssl, &cbb)) { goto err; } return 1; err: CBB_cleanup(&cbb); return 0; }