diff --git a/lib/crypto.js b/lib/crypto.js index cec0b2c094fa..03edd08095b3 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -44,6 +44,10 @@ const pendingDeprecation = getOptionValue('--pending-deprecation'); const { fipsMode } = internalBinding('config'); const fipsForced = getOptionValue('--force-fips'); const { getFipsCrypto, setFipsCrypto } = internalBinding('crypto'); +const { parseX509 } = internalBinding('crypto'); +const { + isArrayBufferView, +} = require('internal/util/types'); const { randomBytes, randomFill, @@ -150,6 +154,13 @@ function createVerify(algorithm, options) { return new Verify(algorithm, options); } +function parseCert(cert) { + if (!isArrayBufferView(cert)) { + throw new ERR_INVALID_ARG_TYPE('cert', 'ArrayBufferView', buf); + } + return parseX509(cert); +} + module.exports = { // Methods createCipheriv, @@ -190,6 +201,7 @@ module.exports = { setFips: !fipsMode ? setFipsDisabled : fipsForced ? setFipsForced : setFipsCrypto, verify: verifyOneShot, + parseCert, // Classes Certificate, diff --git a/src/node_crypto.cc b/src/node_crypto.cc index b589eac6947b..840ab9a43275 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -1145,7 +1145,6 @@ static void IsExtraRootCertsFileLoaded( return args.GetReturnValue().Set(extra_root_certs_loaded); } - void SecureContext::AddRootCerts(const FunctionCallbackInfo& args) { SecureContext* sc; ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); @@ -2176,6 +2175,39 @@ static Local X509ToObject(Environment* env, X509* cert) { } +static void ParseX509(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + + CHECK(args[0]->IsArrayBufferView()); + ArrayBufferViewContents buf(args[0].As()); + const unsigned char* data = buf.data(); + unsigned data_len = buf.length(); + + ClearErrorOnReturn clear_error_on_return; + BIOPointer bio(LoadBIO(env, args[0])); + if (!bio) + return ThrowCryptoError(env, ERR_get_error()); + + X509Pointer pem(PEM_read_bio_X509_AUX( + bio.get(), nullptr, NoPasswordCallback, nullptr)); + + if (!pem) { + // Try as DER, but return the original PEM failure if it isn't DER. + MarkPopErrorOnReturn mark_here; + + X509Pointer der(d2i_X509(nullptr, &data, data_len)); + if (der) { + args.GetReturnValue().Set(X509ToObject(env, der.get())); + } + } + if (!pem) { + return ThrowCryptoError(env, ERR_get_error()); + } + + args.GetReturnValue().Set(X509ToObject(env, pem.get())); +} + + static Local AddIssuerChainToObject(X509Pointer* cert, Local object, StackOfX509&& peer_certs, @@ -7358,6 +7390,8 @@ void Initialize(Local target, // Exposed for testing purposes only. env->SetMethodNoSideEffect(target, "isExtraRootCertsFileLoaded", IsExtraRootCertsFileLoaded); + env->SetMethodNoSideEffect(target, "parseX509", + ParseX509); env->SetMethodNoSideEffect(target, "ECDHConvertKey", ConvertKey); #ifndef OPENSSL_NO_ENGINE