[PATCH] crypto: Treat ASN1_STRING as an opaque type

Xiangfei Ding xfding at google.com
Thu Oct 22 03:02:44 PDT 2026


OpenSSL has published migration guide mentioning that the type is
turning opaque. One should use accessor functions instead.

See migration guide [1] [2].

[1] https://docs.openssl.org/master/man7/ossl-guide-migration/#asn1_string-values-have-never-been-nul-byte-terminated
[2] https://docs.openssl.org/master/man7/ossl-guide-migration/#the-asn1_string-type-is-now-opaque

Signed-off-by: Xiangfei Ding <xfding at google.com>
---
 src/crypto/crypto_openssl.c   |  8 +---
 src/crypto/tls_openssl.c      | 82 ++++++++++++++++++++++-------------
 src/crypto/tls_openssl_ocsp.c | 15 ++++---
 3 files changed, 64 insertions(+), 41 deletions(-)

diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index f67d46e9e..29a391ab7 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -3784,14 +3784,8 @@ struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
 	len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
 				 der, len, ctx);
 
-	OPENSSL_free(pubkey->pub_key->data);
-	pubkey->pub_key->data = der;
+	ASN1_STRING_set0(pubkey->pub_key, der, len);
 	der = NULL;
-	pubkey->pub_key->length = len;
-	/* No unused bits */
-	pubkey->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
-	pubkey->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
-
 	der_len = i2d_EC_COMP_PUBKEY(pubkey, &der);
 	if (der_len <= 0) {
 		wpa_printf(MSG_ERROR,
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 032bf05f2..0c7eb60c8 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -2088,6 +2088,8 @@ char * tls_connection_peer_serial_num(void *tls_ctx,
 				      struct tls_connection *conn)
 {
 	ASN1_INTEGER *ser;
+	const unsigned char *ser_data;
+	int ser_len;
 	char *serial_num;
 	size_t len;
 
@@ -2098,13 +2100,13 @@ char * tls_connection_peer_serial_num(void *tls_ctx,
 	if (!ser)
 		return NULL;
 
-	len = ASN1_STRING_length(ser) * 2 + 1;
+	ser_data = ASN1_STRING_get0_data(ser);
+	ser_len = ASN1_STRING_length(ser);
+	len = (size_t) ser_len * 2 + 1;
 	serial_num = os_malloc(len);
 	if (!serial_num)
 		return NULL;
-	wpa_snprintf_hex_uppercase(serial_num, len,
-				   ASN1_STRING_get0_data(ser),
-				   ASN1_STRING_length(ser));
+	wpa_snprintf_hex_uppercase(serial_num, len, ser_data, ser_len);
 	return serial_num;
 }
 
@@ -2296,6 +2298,8 @@ static int match_dn_field(const X509 *cert, int nid, const char *field,
 						     i)) > -1;) {
 		const X509_NAME_ENTRY *e;
 		const ASN1_STRING *cn;
+		const unsigned char *cn_data;
+		int cn_len;
 
 		e = X509_NAME_get_entry(name, i);
 		if (!e)
@@ -2311,6 +2315,9 @@ static int match_dn_field(const X509 *cert, int nid, const char *field,
 		if (match_index != config_dn_field_index)
 			continue;
 
+		cn_data = ASN1_STRING_get0_data(cn);
+		cn_len = ASN1_STRING_length(cn);
+
 		/* Check wildcard at the right end side */
 		/* E.g., if OU=develop* mentioned in configuration, allow 'OU'
 		 * of the subject in the client certificate to start with
@@ -2319,20 +2326,18 @@ static int match_dn_field(const X509 *cert, int nid, const char *field,
 			/* Compare actual certificate DN field value with
 			 * configuration DN field value up to the specified
 			 * length. */
-			ret = ASN1_STRING_length(cn) >= len - 1 &&
-				os_memcmp(ASN1_STRING_get0_data(cn), value,
-					  len - 1) == 0;
+			ret = (size_t) cn_len >= len - 1 &&
+				os_memcmp(cn_data, value, len - 1) == 0;
 		} else {
 			/* Compare actual certificate DN field value with
 			 * configuration DN field value */
-			ret = ASN1_STRING_length(cn) == len &&
-				os_memcmp(ASN1_STRING_get0_data(cn), value,
-					  len) == 0;
+			ret = (size_t) cn_len == len && os_memcmp(cn_data, value, len) == 0;
 		}
 		if (!ret) {
 			wpa_printf(MSG_ERROR,
-				   "OpenSSL: Failed to match %s '%s' with certificate DN field value '%s'",
-				   field, value, ASN1_STRING_get0_data(cn));
+				   "OpenSSL: Failed to match %s '%s' with certificate DN field"
+				   " value '%.*s'",
+				   field, value, cn_len, (const char *) cn_data);
 		}
 		break;
 	}
@@ -2458,15 +2463,22 @@ static int tls_match_suffix_helper(X509 *cert, const char *match,
 	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
 
 	for (j = 0; ext && j < sk_GENERAL_NAME_num(ext); j++) {
+		const unsigned char *dns_data;
+		int dns_len;
+
 		gen = sk_GENERAL_NAME_value(ext, j);
-		if (gen->type != GEN_DNS)
+		if (gen->type != GEN_DNS || !gen->d.dNSName)
+			continue;
+
+		dns_data = ASN1_STRING_get0_data(gen->d.dNSName);
+		dns_len = ASN1_STRING_length(gen->d.dNSName);
+		if (!dns_data)
 			continue;
+
 		dns_name++;
 		wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
-				  ASN1_STRING_get0_data(gen->d.dNSName),
-				  ASN1_STRING_length(gen->d.dNSName));
-		if (domain_suffix_match(ASN1_STRING_get0_data(gen->d.dNSName),
-					ASN1_STRING_length(gen->d.dNSName),
+				  dns_data, dns_len);
+		if (domain_suffix_match(dns_data, dns_len,
 					match, match_len, full) == 1) {
 			wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
 				   full ? "Match" : "Suffix match");
@@ -2486,6 +2498,8 @@ static int tls_match_suffix_helper(X509 *cert, const char *match,
 	for (;;) {
 		const X509_NAME_ENTRY *e;
 		const ASN1_STRING *cn;
+		const unsigned char *cn_data;
+		int cn_len;
 
 		i = X509_NAME_get_index_by_NID((X509_NAME *) name,
 					       NID_commonName, i);
@@ -2497,11 +2511,11 @@ static int tls_match_suffix_helper(X509 *cert, const char *match,
 		cn = X509_NAME_ENTRY_get_data(e);
 		if (cn == NULL)
 			continue;
+		cn_data = ASN1_STRING_get0_data(cn);
+		cn_len = ASN1_STRING_length(cn);
 		wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
-				  ASN1_STRING_get0_data(cn),
-				  ASN1_STRING_length(cn));
-		if (domain_suffix_match(ASN1_STRING_get0_data(cn),
-					ASN1_STRING_length(cn),
+				  cn_data, cn_len);
+		if (domain_suffix_match(cn_data, cn_len,
 					match, match_len, full) == 1) {
 			wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
 				   full ? "Match" : "Suffix match");
@@ -2701,6 +2715,8 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
 	ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
 	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
 		char *pos;
+		const unsigned char *ia5_data;
+		int ia5_len;
 
 		if (num_altsubject == TLS_MAX_ALT_SUBJECT)
 			break;
@@ -2710,7 +2726,15 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
 		    gen->type != GEN_URI)
 			continue;
 
-		pos = os_malloc(10 + ASN1_STRING_length(gen->d.ia5) + 1);
+		if (!gen->d.ia5)
+			continue;
+
+		ia5_data = ASN1_STRING_get0_data(gen->d.ia5);
+		ia5_len = ASN1_STRING_length(gen->d.ia5);
+		if (!ia5_data)
+			continue;
+
+		pos = os_malloc(10 + ia5_len + 1);
 		if (pos == NULL)
 			break;
 		altsubject[num_altsubject++] = pos;
@@ -2730,9 +2754,8 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
 			break;
 		}
 
-		os_memcpy(pos, ASN1_STRING_get0_data(gen->d.ia5),
-			  ASN1_STRING_length(gen->d.ia5));
-		pos += ASN1_STRING_length(gen->d.ia5);
+		os_memcpy(pos, ia5_data, ia5_len);
+		pos += ia5_len;
 		*pos = '\0';
 	}
 	sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
@@ -6063,11 +6086,12 @@ static void openssl_debug_dump_certificate(int i, X509 *cert)
 	X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
 
 	ser = X509_get_serialNumber(cert);
-	if (ser)
+	if (ser) {
+		const unsigned char *ser_data = ASN1_STRING_get0_data(ser);
+		int ser_len = ASN1_STRING_length(ser);
 		wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
-					   ASN1_STRING_get0_data(ser),
-					   ASN1_STRING_length(ser));
-	else
+					   ser_data, ser_len);
+	} else
 		serial_num[0] = '\0';
 
 	pkey = X509_get_pubkey(cert);
diff --git a/src/crypto/tls_openssl_ocsp.c b/src/crypto/tls_openssl_ocsp.c
index 7780b71fd..5c9bd8113 100644
--- a/src/crypto/tls_openssl_ocsp.c
+++ b/src/crypto/tls_openssl_ocsp.c
@@ -428,7 +428,8 @@ static int issuer_match(X509 *cert, X509 *issuer, CertID *certid)
 
 	ikey = X509_get0_pubkey_bitstr(issuer);
 	if (!ikey ||
-	    !EVP_Digest(ikey->data, ikey->length, md, &len, dgst, NULL) ||
+		!EVP_Digest(ASN1_STRING_get0_data(ikey), ASN1_STRING_length(ikey),
+			md, &len, dgst, NULL) ||
 	    !ASN1_OCTET_STRING_set(hash, md, len)) {
 		ASN1_OCTET_STRING_free(hash);
 		return -1;
@@ -455,6 +456,7 @@ static X509 * ocsp_find_signer(STACK_OF(X509) *certs, ResponderID *rid)
 {
 	int i;
 	unsigned char hash[SHA_DIGEST_LENGTH];
+	const unsigned char *key_data;
 
 	if (rid->type == 0) {
 		/* byName */
@@ -462,14 +464,17 @@ static X509 * ocsp_find_signer(STACK_OF(X509) *certs, ResponderID *rid)
 	}
 
 	/* byKey */
-	if (rid->value.byKey->length != SHA_DIGEST_LENGTH)
+	if (!rid->value.byKey ||
+	    ASN1_STRING_length(rid->value.byKey) != SHA_DIGEST_LENGTH)
+		return NULL;
+	key_data = ASN1_STRING_get0_data(rid->value.byKey);
+	if (!key_data)
 		return NULL;
 	for (i = 0; i < sk_X509_num(certs); i++) {
 		X509 *x = sk_X509_value(certs, i);
 
 		X509_pubkey_digest(x, EVP_sha1(), hash, NULL);
-		if (os_memcmp(rid->value.byKey->data, hash,
-			      SHA_DIGEST_LENGTH) == 0)
+		if (os_memcmp(key_data, hash, SHA_DIGEST_LENGTH) == 0)
 			return x;
 	}
 
@@ -540,7 +545,7 @@ enum ocsp_result check_ocsp_resp(SSL_CTX *ssl_ctx, SSL *ssl, X509 *cert,
 		return OCSP_INVALID;
 	}
 
-	basic_data = ASN1_STRING_data(bytes->response);
+	basic_data = ASN1_STRING_get0_data(bytes->response);
 	basic_len = ASN1_STRING_length(bytes->response);
 	wpa_hexdump(MSG_DEBUG, "OpenSSL: BasicOCSPResponse",
 		    basic_data, basic_len);
-- 
2.56.0.218.g1ec904b173-goog




More information about the Hostap mailing list