Skip to content

Commit a62b7d5

Browse files
panvamcollina
authored andcommitted
crypto: harden X.509 conversion and formatting
Check X.509 ASN.1, BIO, time, OID, and DER conversion results. Preserve invalid-time diagnostics, reject incomplete BIO writes, format RSA exponents atomically, and avoid truncating long object identifiers. Preserve valid siblings in legacy name objects by omitting individual non-text AttributeValues. Continue treating structural failures and failed conversion of supported string types as conversion failures. Reject empty or malformed SAN and AIA extensions, and prevent TLS hostname checks from falling back to commonName after a malformed SAN. Guard missing public keys and non-NIST curve names. Scope fallible backend probes without consuming callback errors, parse checkIP() inputs to exact address bytes, and preserve unrelated backend errors. Refs: https://hackerone.com/reports/3910015 Refs: https://hackerone.com/reports/3824331 Refs: https://hackerone.com/reports/3944830 Refs: https://hackerone.com/reports/3944847 Assisted-by: Codex Co-authored-by: Matteo Collina <hello@matteocollina.com> Signed-off-by: Matteo Collina <hello@matteocollina.com> Signed-off-by: Filip Skokan <panva.ip@gmail.com> Backport-PR-URL: nodejs-private/node-private#1006 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> PR-URL: nodejs-private/node-private#966
1 parent ec9e5e4 commit a62b7d5

8 files changed

Lines changed: 977 additions & 231 deletions

File tree

‎deps/ncrypto/ncrypto.cc‎

Lines changed: 250 additions & 112 deletions
Large diffs are not rendered by default.

‎deps/ncrypto/ncrypto.h‎

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -344,10 +344,37 @@ class BIOPointer final {
344344

345345
static int Write(BIOPointer* bio, std::string_view message);
346346

347+
// Writes the complete message and returns false if any bytes were not
348+
// written.
349+
static bool WriteAll(const BIOPointer& bio, std::string_view message);
350+
351+
// Returns the number of bytes written, or a negative value on error.
352+
template <typename... Args>
353+
static int Printf(BIOPointer* bio, const char* format, Args... args) {
354+
if (bio == nullptr || !*bio) return -1;
355+
return BIO_printf(bio->get(), format, std::forward<Args>(args)...);
356+
}
357+
358+
// Formats and writes the complete message, returning false if formatting
359+
// fails or any bytes were not written.
347360
template <typename... Args>
348-
static void Printf(BIOPointer* bio, const char* format, Args... args) {
349-
if (bio == nullptr || !*bio) return;
350-
BIO_printf(bio->get(), format, std::forward<Args...>(args...));
361+
static bool PrintfAll(const BIOPointer& bio,
362+
const char* format,
363+
Args... args) {
364+
if (!bio) return false;
365+
366+
BIOPointer formatted = NewMem();
367+
if (!formatted) return false;
368+
int length =
369+
BIO_printf(formatted.get(), format, std::forward<Args>(args)...);
370+
if (length < 0) return false;
371+
372+
BUF_MEM* mem = formatted;
373+
if (mem == nullptr || mem->length != static_cast<size_t>(length)) {
374+
return false;
375+
}
376+
if (length == 0) return true;
377+
return WriteAll(bio, std::string_view(mem->data, mem->length));
351378
}
352379

353380
private:
@@ -760,13 +787,13 @@ class X509View final {
760787
BIOPointer toDER() const;
761788

762789
BIOPointer getSubject() const;
763-
BIOPointer getSubjectAltName() const;
790+
BIOPointer getSubjectAltName(bool* has_extension = nullptr) const;
764791
BIOPointer getIssuer() const;
765792
BIOPointer getInfoAccess() const;
766793
BIOPointer getValidFrom() const;
767794
BIOPointer getValidTo() const;
768-
int64_t getValidFromTime() const;
769-
int64_t getValidToTime() const;
795+
std::optional<int64_t> getValidFromTime() const;
796+
std::optional<int64_t> getValidToTime() const;
770797
DataPointer getSerialNumber() const;
771798
Result<EVPKeyPointer, int> getPublicKey() const;
772799
StackOfASN1 getKeyUsage() const;
@@ -790,7 +817,7 @@ class X509View final {
790817
int flags,
791818
DataPointer* peerName = nullptr) const;
792819
CheckMatch checkEmail(const std::string_view email, int flags) const;
793-
CheckMatch checkIp(const std::string_view ip, int flags) const;
820+
CheckMatch checkIp(const Buffer<const unsigned char>& ip, int flags) const;
794821

795822
private:
796823
const X509* cert_ = nullptr;
@@ -1009,8 +1036,9 @@ int NoPasswordCallback(char* buf, int size, int rwflag, void* u);
10091036

10101037
int PasswordCallback(char* buf, int size, int rwflag, void* u);
10111038

1012-
bool SafeX509SubjectAltNamePrint(const BIOPointer& out, X509_EXTENSION* ext);
1013-
bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext);
1039+
bool SafeX509SubjectAltNamePrint(const BIOPointer& out,
1040+
const X509_EXTENSION* ext);
1041+
bool SafeX509InfoAccessPrint(const BIOPointer& out, const X509_EXTENSION* ext);
10141042

10151043
// ============================================================================
10161044
// SPKAC

0 commit comments

Comments
 (0)