Factor out certificate list parsing.
This is already duplicated between client and server and otherwise will
get duplicated yet again for TLS 1.3.
Change-Id: Ia8a352f9bc76fab0f88c1629d08a1da4c13d2510
Reviewed-on: https://boringssl-review.googlesource.com/8778
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index aab8610..952bf45 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -122,6 +122,7 @@
#include <openssl/dh.h>
#include <openssl/err.h>
#include <openssl/mem.h>
+#include <openssl/sha.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
@@ -421,6 +422,59 @@
return ssl->cert->x509 != NULL && ssl_has_private_key(ssl);
}
+STACK_OF(X509) *ssl_parse_cert_chain(SSL *ssl, uint8_t *out_alert,
+ uint8_t *out_leaf_sha256, CBS *cbs) {
+ STACK_OF(X509) *ret = sk_X509_new_null();
+ if (ret == NULL) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ X509 *x = NULL;
+ CBS certificate_list;
+ if (!CBS_get_u24_length_prefixed(cbs, &certificate_list)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto err;
+ }
+
+ while (CBS_len(&certificate_list) > 0) {
+ CBS certificate;
+ if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
+ goto err;
+ }
+
+ /* Retain the hash of the leaf certificate if requested. */
+ if (sk_X509_num(ret) == 0 && out_leaf_sha256 != NULL) {
+ SHA256(CBS_data(&certificate), CBS_len(&certificate), out_leaf_sha256);
+ }
+
+ /* A u24 length cannot overflow a long. */
+ const uint8_t *data = CBS_data(&certificate);
+ x = d2i_X509(NULL, &data, (long)CBS_len(&certificate));
+ if (x == NULL || data != CBS_data(&certificate) + CBS_len(&certificate)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ goto err;
+ }
+ if (!sk_X509_push(ret, x)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ x = NULL;
+ }
+
+ return ret;
+
+err:
+ X509_free(x);
+ sk_X509_pop_free(ret, X509_free);
+ return NULL;
+}
+
int ssl_add_cert_to_cbb(CBB *cbb, X509 *x509) {
int len = i2d_X509(x509, NULL);
if (len < 0) {