Indirect stderr through a function

This is the only instance of BCM consuming a non-code external symbol.

Bug: 362530616
Change-Id: Iefc555092c5278e9b3c3c9d894a2bc84ecb9d875
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/70847
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/bcm_support.h b/crypto/bcm_support.h
index c91bcb0..ab10ed4 100644
--- a/crypto/bcm_support.h
+++ b/crypto/bcm_support.h
@@ -17,6 +17,8 @@
 
 #include <openssl/base.h>
 
+#include <stdio.h>
+
 // Provided by libcrypto, called from BCM
 
 #if defined(__cplusplus)
@@ -105,6 +107,10 @@
 OPENSSL_EXPORT void CRYPTO_fork_detect_force_madv_wipeonfork_for_testing(
     int on);
 
+// CRYPTO_get_stderr returns stderr. This function exists to avoid BCM needing
+// a data dependency on libc.
+FILE *CRYPTO_get_stderr(void);
+
 
 #if defined(__cplusplus)
 }  // extern C
diff --git a/crypto/crypto.c b/crypto/crypto.c
index 155e7b4..2e53e74 100644
--- a/crypto/crypto.c
+++ b/crypto/crypto.c
@@ -15,6 +15,7 @@
 #include <openssl/crypto.h>
 
 #include <assert.h>
+#include <stdio.h>
 
 #include "fipsmodule/rand/internal.h"
 #include "bcm_support.h"
@@ -186,3 +187,5 @@
 }
 
 void OPENSSL_cleanup(void) {}
+
+FILE *CRYPTO_get_stderr(void) { return stderr; }
diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c
index 55375ea..0d55c08 100644
--- a/crypto/fipsmodule/bcm.c
+++ b/crypto/fipsmodule/bcm.c
@@ -29,6 +29,7 @@
 #include <openssl/sha.h>
 
 #include "bcm_interface.h"
+#include "../bcm_support.h"
 #include "../internal.h"
 
 // TODO(crbug.com/362530616): When delocate is removed, build these files as
@@ -136,7 +137,7 @@
   }
 
   fprintf(
-      stderr,
+      CRYPTO_get_stderr(),
       "FIPS module doesn't span expected symbol. Expected %p <= %p < %p\n",
       start, symbol, end);
   BORINGSSL_FIPS_abort();
@@ -224,7 +225,7 @@
   HMAC_CTX_init(&hmac_ctx);
   if (!HMAC_Init_ex(&hmac_ctx, kHMACKey, sizeof(kHMACKey), kHashFunction,
                     NULL /* no ENGINE */)) {
-    fprintf(stderr, "HMAC_Init_ex failed.\n");
+    fprintf(CRYPTO_get_stderr(), "HMAC_Init_ex failed.\n");
     return 0;
   }
 
@@ -244,7 +245,7 @@
 
   if (!HMAC_Final(&hmac_ctx, result, &result_len) ||
       result_len != sizeof(result)) {
-    fprintf(stderr, "HMAC failed.\n");
+    fprintf(CRYPTO_get_stderr(), "HMAC failed.\n");
     return 0;
   }
   HMAC_CTX_cleanse(&hmac_ctx); // FIPS 140-3, AS05.10.
diff --git a/crypto/fipsmodule/rand/rand.c.inc b/crypto/fipsmodule/rand/rand.c.inc
index 8adcffe..5e093ec 100644
--- a/crypto/fipsmodule/rand/rand.c.inc
+++ b/crypto/fipsmodule/rand/rand.c.inc
@@ -275,7 +275,7 @@
   // rate of failure is small enough not to be a problem in practice.
   if (CRYPTO_memcmp(state->last_block, entropy, sizeof(state->last_block)) ==
       0) {
-    fprintf(stderr, "CRNGT failed.\n");
+    fprintf(CRYPTO_get_stderr(), "CRNGT failed.\n");
     BORINGSSL_FIPS_abort();
   }
 
@@ -283,7 +283,7 @@
   for (size_t i = CRNGT_BLOCK_SIZE; i < entropy_len; i += CRNGT_BLOCK_SIZE) {
     if (CRYPTO_memcmp(entropy + i - CRNGT_BLOCK_SIZE, entropy + i,
                       CRNGT_BLOCK_SIZE) == 0) {
-      fprintf(stderr, "CRNGT failed.\n");
+      fprintf(CRYPTO_get_stderr(), "CRNGT failed.\n");
       BORINGSSL_FIPS_abort();
     }
   }
diff --git a/crypto/fipsmodule/self_check/self_check.c.inc b/crypto/fipsmodule/self_check/self_check.c.inc
index 509634c..08a36be 100644
--- a/crypto/fipsmodule/self_check/self_check.c.inc
+++ b/crypto/fipsmodule/self_check/self_check.c.inc
@@ -32,6 +32,7 @@
 #include <openssl/rsa.h>
 #include <openssl/sha.h>
 
+#include "../../bcm_support.h"
 #include "../../internal.h"
 #include "../delocate.h"
 #include "../dh/internal.h"
@@ -53,21 +54,22 @@
 
 #else
 
-static void hexdump(const uint8_t *in, size_t len) {
+static void hexdump(FILE *out, const uint8_t *in, size_t len) {
   for (size_t i = 0; i < len; i++) {
-    fprintf(stderr, "%02x", in[i]);
+    fprintf(out, "%02x", in[i]);
   }
 }
 
 static int check_test(const void *expected, const void *actual,
                       size_t expected_len, const char *name) {
   if (OPENSSL_memcmp(actual, expected, expected_len) != 0) {
-    fprintf(stderr, "%s failed.\nExpected:   ", name);
-    hexdump(expected, expected_len);
-    fprintf(stderr, "\nCalculated: ");
-    hexdump(actual, expected_len);
-    fprintf(stderr, "\n");
-    fflush(stderr);
+    FILE *err = CRYPTO_get_stderr();
+    fprintf(err, "%s failed.\nExpected:   ", name);
+    hexdump(err, expected, expected_len);
+    fprintf(err, "\nCalculated: ");
+    hexdump(err, actual, expected_len);
+    fprintf(err, "\n");
+    fflush(err);
     return 0;
   }
   return 1;
@@ -294,7 +296,7 @@
 
   RSA *const rsa_key = self_test_rsa_key();
   if (rsa_key == NULL) {
-    fprintf(stderr, "RSA key construction failed\n");
+    fprintf(CRYPTO_get_stderr(), "RSA key construction failed\n");
     goto err;
   }
   // Disable blinding for the power-on tests because it's not needed and
@@ -338,7 +340,7 @@
                              output, &sig_len, rsa_key) ||
       !check_test(kRSASignSignature, output, sizeof(kRSASignSignature),
                   "RSA-sign KAT")) {
-    fprintf(stderr, "RSA signing test failed.\n");
+    fprintf(CRYPTO_get_stderr(), "RSA signing test failed.\n");
     goto err;
   }
 
@@ -376,7 +378,7 @@
   if (!rsa_verify_no_self_test(NID_sha256, kRSAVerifyDigest,
                                sizeof(kRSAVerifyDigest), kRSAVerifySignature,
                                sizeof(kRSAVerifySignature), rsa_key)) {
-    fprintf(stderr, "RSA-verify KAT failed.\n");
+    fprintf(CRYPTO_get_stderr(), "RSA-verify KAT failed.\n");
     goto err;
   }
 
@@ -397,7 +399,7 @@
 
   ec_key = self_test_ecdsa_key();
   if (ec_key == NULL) {
-    fprintf(stderr, "ECDSA KeyGen failed\n");
+    fprintf(CRYPTO_get_stderr(), "ECDSA KeyGen failed\n");
     goto err;
   }
 
@@ -429,7 +431,7 @@
           sizeof(ecdsa_k)) ||
       !check_test(kECDSASignSig, ecdsa_sign_output, sizeof(ecdsa_sign_output),
                   "ECDSA-sign signature")) {
-    fprintf(stderr, "ECDSA-sign KAT failed.\n");
+    fprintf(CRYPTO_get_stderr(), "ECDSA-sign KAT failed.\n");
     goto err;
   }
 
@@ -450,7 +452,7 @@
   if (!ecdsa_verify_fixed_no_self_test(
           kECDSAVerifyDigest, sizeof(kECDSAVerifyDigest), kECDSAVerifySig,
           sizeof(kECDSAVerifySig), ec_key)) {
-    fprintf(stderr, "ECDSA-verify KAT failed.\n");
+    fprintf(CRYPTO_get_stderr(), "ECDSA-verify KAT failed.\n");
     goto err;
   }
 
@@ -496,7 +498,7 @@
                           z_comp_result, sizeof(z_comp_result), NULL) ||
       !check_test(kP256PointResult, z_comp_result, sizeof(z_comp_result),
                   "Z Computation Result")) {
-    fprintf(stderr, "Z-computation KAT failed.\n");
+    fprintf(CRYPTO_get_stderr(), "Z-computation KAT failed.\n");
     goto err;
   }
 
@@ -575,7 +577,7 @@
       dh_compute_key_padded_no_self_test(dh_out, ffdhe2048_value, dh) !=
           sizeof(dh_out) ||
       !check_test(kDHOutput, dh_out, sizeof(dh_out), "FFC DH")) {
-    fprintf(stderr, "FFDH failed.\n");
+    fprintf(CRYPTO_get_stderr(), "FFDH failed.\n");
     goto err;
   }
 
@@ -723,7 +725,7 @@
   };
   memcpy(aes_iv, kAESIV, sizeof(kAESIV));
   if (AES_set_encrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) != 0) {
-    fprintf(stderr, "AES_set_encrypt_key failed.\n");
+    fprintf(CRYPTO_get_stderr(), "AES_set_encrypt_key failed.\n");
     goto err;
   }
   AES_cbc_encrypt(kAESCBCEncPlaintext, output, sizeof(kAESCBCEncPlaintext),
@@ -746,7 +748,7 @@
   };
   memcpy(aes_iv, kAESIV, sizeof(kAESIV));
   if (AES_set_decrypt_key(kAESKey, 8 * sizeof(kAESKey), &aes_key) != 0) {
-    fprintf(stderr, "AES_set_decrypt_key failed.\n");
+    fprintf(CRYPTO_get_stderr(), "AES_set_decrypt_key failed.\n");
     goto err;
   }
   AES_cbc_encrypt(kAESCBCDecCiphertext, output, sizeof(kAESCBCDecCiphertext),
@@ -761,7 +763,7 @@
   OPENSSL_memset(nonce, 0, sizeof(nonce));
   if (!EVP_AEAD_CTX_init(&aead_ctx, EVP_aead_aes_128_gcm(), kAESKey,
                          sizeof(kAESKey), 0, NULL)) {
-    fprintf(stderr, "EVP_AEAD_CTX_init for AES-128-GCM failed.\n");
+    fprintf(CRYPTO_get_stderr(), "EVP_AEAD_CTX_init for AES-128-GCM failed.\n");
     goto err;
   }
 
@@ -783,7 +785,7 @@
                          0) ||
       !check_test(kAESGCMCiphertext, output, sizeof(kAESGCMCiphertext),
                   "AES-GCM-encrypt KAT")) {
-    fprintf(stderr, "EVP_AEAD_CTX_seal for AES-128-GCM failed.\n");
+    fprintf(CRYPTO_get_stderr(), "EVP_AEAD_CTX_seal for AES-128-GCM failed.\n");
     goto err;
   }
 
@@ -806,7 +808,7 @@
                          NULL, 0) ||
       !check_test(kAESGCMDecPlaintext, output, sizeof(kAESGCMDecPlaintext),
                   "AES-GCM-decrypt KAT")) {
-    fprintf(stderr,
+    fprintf(CRYPTO_get_stderr(),
             "AES-GCM-decrypt KAT failed because EVP_AEAD_CTX_open failed.\n");
     goto err;
   }
@@ -875,7 +877,7 @@
                          sizeof(kDRBGAD)) ||
       !check_test(kDRBGReseedOutput, output, sizeof(kDRBGReseedOutput),
                   "DRBG-reseed KAT")) {
-    fprintf(stderr, "CTR-DRBG failed.\n");
+    fprintf(CRYPTO_get_stderr(), "CTR-DRBG failed.\n");
     goto err;
   }
   CTR_DRBG_clear(&drbg);
@@ -914,7 +916,7 @@
                        kTLSSeed2, sizeof(kTLSSeed2)) ||
       !check_test(kTLS10Output, tls10_output, sizeof(kTLS10Output),
                   "TLS10-KDF KAT")) {
-    fprintf(stderr, "TLS KDF failed.\n");
+    fprintf(CRYPTO_get_stderr(), "TLS KDF failed.\n");
     goto err;
   }
 
@@ -935,7 +937,7 @@
                        kTLSSeed2, sizeof(kTLSSeed2)) ||
       !check_test(kTLS12Output, tls12_output, sizeof(kTLS12Output),
                   "TLS12-KDF KAT")) {
-    fprintf(stderr, "TLS KDF failed.\n");
+    fprintf(CRYPTO_get_stderr(), "TLS KDF failed.\n");
     goto err;
   }
 
@@ -975,7 +977,7 @@
       !check_test(kTLS13ExpandLabelOutput, tls13_expand_label_output,
                   sizeof(kTLS13ExpandLabelOutput),
                   "CRYPTO_tls13_hkdf_expand_label")) {
-    fprintf(stderr, "TLS13-KDF failed.\n");
+    fprintf(CRYPTO_get_stderr(), "TLS13-KDF failed.\n");
     goto err;
   }
 
@@ -1005,7 +1007,7 @@
             sizeof(kHKDFSecret), kHKDFSalt, sizeof(kHKDFSalt), kHKDFInfo,
             sizeof(kHKDFInfo)) ||
       !check_test(kHKDFOutput, hkdf_output, sizeof(kHKDFOutput), "HKDF")) {
-    fprintf(stderr, "HKDF failed.\n");
+    fprintf(CRYPTO_get_stderr(), "HKDF failed.\n");
     goto err;
   }