Skip to content

[Bug]: Invalid CSR generated by ESP32s3 #6205

@PaulMartinsen

Description

@PaulMartinsen

Contact Details

No response

Version

Jim/ED25519_SHA2_fix

Description

Library creates an invalid certificate signing request on the ESP32s3 when hardware acceleration is enabled. A valid signing request is generated with hardware acceleration disabled, or the code running on a Windows target. Previously I've seen the same problem on the ESP32 and even with hardware acceleration disabled. Have tested on a recent master branch and also ED25519_SHA2_fix. I used @gojimmypi 's branch as he has a lot of fixes for the Espressif implementation of the library.

Output from the signing command when supplied with a good CSR (ESP32s3 without h/w acceleration):

$ openssl.ex
[user_settings.zip](https://github.com/wolfSSL/wolfssl/files/11007185/user_settings.zip)
e x509 -req -in "Input\BLS-001 - ESP32s3 - no HW acceleration - new key - signing request.csr" -days 10   -CA "CertificateAuthority-4096-PublicKey.crt" -CAkey "CertificateAuthority-4096-PrivateKey.pem" -passin pass:secret -CAcreateserial   -extfile "CertificateExtensions.txt" -extensions LumosDevice   -out Output\BLS-001-Device-Certificate.crt -text
Certificate request self-signature ok
subject=C = NZ, L = Hamilton, O = "Blue Leaf Software, Ltd", CN = Lumos, serialNumber = BLS-001

Output from the signing command when supplied with a bad CSR (ESP32s3 with h/w acceleration):

$ openssl.exe x509 -req -in "Input\BLS-001 - ESP32s3 - HW acceleration - New private key - Jim ED25519_SHA2_fix -signing request.csr" -days 10   -CA "CertificateAuthority-4096-PublicKey.crt" -CAkey "CertificateAuthority-4096-PrivateKey.pem" -passin pass:secret -CAcreateserial   -extfile "CertificateExtensions.txt" -extensions LumosDevice   -out Output\BLS-001-Device-Certificate.crt -text
Certificate request self-signature did not match the contents
545B0000:error:0200008A:rsa routines:RSA_padding_check_PKCS1_type_1:invalid padding:crypto\rsa\rsa_pk1.c:75:
545B0000:error:02000072:rsa routines:rsa_ossl_public_decrypt:padding check failed:crypto\rsa\rsa_ossl.c:599:
545B0000:error:1C880004:Provider routines:rsa_verify:RSA lib:providers\implementations\signature\rsa_sig.c:774:
545B0000:error:06880006:asn1 encoding routines:ASN1_item_verify_ctx:EVP lib:crypto\asn1\a_verify.c:217:

If I take the private key that's generated on the device I can create a CSR as below (in Windows), but that produces the same error message as above when I try to sign the CSR as above suggesting the problem might be with the private key.
openssl req -new -key "Input\BLS-001 - ESP32s3 - HW acceleration - New private key - Jim ED25519_SHA2_fix.pem" -nodes -out Output\BLS-001-req.csr

Code used to generate a private key and signing request on the device:

bool CCredentialStore::GenerateCertificate(const char* pchSerial, const char* pAddress)
{
  // Generate a new private device key. Using a RSA key because the ESP32 has hardware
  // acceleration for that. 
  // https://www.wolfssl.com/documentation/manuals/wolfssl/chapter07.html#rsa-key-generation
  // https://www.wolfssl.com/documentation/manuals/wolfssl/group__Random.html#function-wc_initrng
  // https://www.wolfssl.com/documentation/manuals/wolfssl/group__RSA.html#function-wc_initrsakey
  // https://www.wolfssl.com/documentation/manuals/wolfssl/group__RSA.html#function-wc_makersakey
  
  // todo: check if this is using the Espressif RNG. If it is, make sure the radio
  // is on. The radio is used as an entropy source to make sure that true random
  // numbers are generated. If it isn't using the Espressif RNG, maybe it should 
  // be since that should generate True Random Numbers. 
  WC_RNG RandomNumberGenerator; 
  int nResult = wc_InitRng(&RandomNumberGenerator);
  if (0 != nResult)
  {
    ReportError("InitRng", nResult);
    return false;
  }

  unique_ptr<RsaKey> pNewKey(new RsaKey());
  nResult = wc_InitRsaKey(pNewKey.get(), nullptr);
  if (0 != nResult)
  {
    ReportError("InitRsaKey", nResult);
    return false;
  }

  nResult = wc_MakeRsaKey(pNewKey.get(), PrivateKeySize, 65537, &RandomNumberGenerator);
  if (0 != nResult)
  {
    ReportError("MakeRsaKey", nResult);
    return false;
  }
  
  const size_t szPrivateKeyBuffer = 2048;
  auto puPrivateKeyDer = make_unique<uint8_t[]>(szPrivateKeyBuffer);
  nResult = wc_RsaKeyToDer(pNewKey.get(), puPrivateKeyDer.get(), szPrivateKeyBuffer);
  if (nResult > 0)
  {
    WriteCertificate(puPrivateKeyDer.get(), nResult, PRIVATEKEY_TYPE);
  }
  else
  {
    cerr << "Error: wc_RsaKeyToDer\n";
  }

  // Generate a certificate signing request. 
  // https://www.wolfssl.com/documentation/manuals/wolfssl/chapter07.html#certificate-signing-request-csr-generation
  // https://www.wolfssl.com/documentation/manuals/wolfssl/asn__public_8h.html#function-wc_makecertreq
  // https://www.wolfssl.com/documentation/manuals/wolfssl/asn__public_8h.html#function-wc_signcert
  unique_ptr<Cert> pRequest(new Cert());
  wc_InitCert(pRequest.get());
  pRequest->daysValid = 30;

#if IS_WINDOWS
  strncpy_s(pRequest->subject.country, "NZ", sizeof(pRequest->subject.country));
  strncpy_s(pRequest->subject.org, "Blue Leaf Software, Ltd", sizeof(pRequest->subject.org));
  strncpy_s(pRequest->subject.locality, "Hamilton", sizeof(pRequest->subject.locality));
  strncpy_s(pRequest->subject.commonName, "Lumos", sizeof(pRequest->subject.commonName));
#else
  strncpy(pRequest->subject.country, "NZ", sizeof(pRequest->subject.country));
  strncpy(pRequest->subject.org, "Blue Leaf Software, Ltd", sizeof(pRequest->subject.org));
  strncpy(pRequest->subject.locality, "Hamilton", sizeof(pRequest->subject.locality));
  strncpy(pRequest->subject.commonName, "Lumos", sizeof(pRequest->subject.commonName));
#endif
  CFixedStringPrint SerialDev(pRequest->subject.serialDev, sizeof(pRequest->subject.serialDev));
  SerialDev << pchSerial;

  const size_t szCertificateRequestBuffer = 4096;
  auto puCertificateRequest = make_unique<uint8_t[]>(szCertificateRequestBuffer);
  int nRequestSize = wc_MakeCertReq(pRequest.get(), puCertificateRequest.get(), szCertificateRequestBuffer, pNewKey.get(), nullptr);
  if (nRequestSize <= 0)
  {
    ReportError("MakeCertReq", nRequestSize);
    return false;
  }

  cout << "SignCert\n";
  pRequest->sigType = CTC_SHA256wRSA;
  int nCertificateSize = wc_SignCert(pRequest->bodySz, pRequest->sigType, puCertificateRequest.get(), szCertificateRequestBuffer, pNewKey.get(), nullptr, &RandomNumberGenerator);
  if (nCertificateSize <= 0)
  {
    ReportError("SignCert", nCertificateSize);
    return false;
  }

  WriteCertificate(puCertificateRequest.get(), nCertificateSize, CERTREQ_TYPE);
  
  cout << "\ndone.\n";

  return true;
}

void CCredentialStore::WriteCertificate(const uint8_t *pDERCertificate, size_t szCertificate, int nType)
{
  const size_t szTextRequestBuffer = 4096;
  auto puTextRequest = make_unique<uint8_t[]>(szTextRequestBuffer);
  memset(puTextRequest.get(), 0, szTextRequestBuffer);
  int nPemSize = wc_DerToPem(pDERCertificate, szCertificate, puTextRequest.get(), szTextRequestBuffer, nType);
  if (nPemSize <= 0 || nPemSize == szTextRequestBuffer)
  {
    ReportError("DerToPem", nPemSize);
    return;
  }

  // make sure null terminated. 
  puTextRequest.get()[nPemSize - 1] = 0;

  cout << reinterpret_cast<char*>(puTextRequest.get()) << endl << endl;
}

Also attached, WolfSSL user_settings.zip files, Keys and certificate signing requests.zip

Reproduction steps

No response

Relevant log output

No response

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions