11cb0ef41Sopenharmony_ci#include "crypto/crypto_spkac.h"
21cb0ef41Sopenharmony_ci#include "crypto/crypto_common.h"
31cb0ef41Sopenharmony_ci#include "crypto/crypto_util.h"
41cb0ef41Sopenharmony_ci#include "env-inl.h"
51cb0ef41Sopenharmony_ci#include "memory_tracker-inl.h"
61cb0ef41Sopenharmony_ci#include "node.h"
71cb0ef41Sopenharmony_ci#include "v8.h"
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_cinamespace node {
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ciusing v8::Context;
121cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo;
131cb0ef41Sopenharmony_ciusing v8::Local;
141cb0ef41Sopenharmony_ciusing v8::Object;
151cb0ef41Sopenharmony_ciusing v8::Value;
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_cinamespace crypto {
181cb0ef41Sopenharmony_cinamespace SPKAC {
191cb0ef41Sopenharmony_cibool VerifySpkac(const ArrayBufferOrViewContents<char>& input) {
201cb0ef41Sopenharmony_ci  size_t length = input.size();
211cb0ef41Sopenharmony_ci#ifdef OPENSSL_IS_BORINGSSL
221cb0ef41Sopenharmony_ci  // OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
231cb0ef41Sopenharmony_ci  // while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
241cb0ef41Sopenharmony_ci  // As such, we trim those characters here for compatibility.
251cb0ef41Sopenharmony_ci  length = std::string(input.data()).find_last_not_of(" \n\r\t") + 1;
261cb0ef41Sopenharmony_ci#endif
271cb0ef41Sopenharmony_ci  NetscapeSPKIPointer spki(
281cb0ef41Sopenharmony_ci      NETSCAPE_SPKI_b64_decode(input.data(), length));
291cb0ef41Sopenharmony_ci  if (!spki)
301cb0ef41Sopenharmony_ci    return false;
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci  EVPKeyPointer pkey(X509_PUBKEY_get(spki->spkac->pubkey));
331cb0ef41Sopenharmony_ci  if (!pkey)
341cb0ef41Sopenharmony_ci    return false;
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci  return NETSCAPE_SPKI_verify(spki.get(), pkey.get()) > 0;
371cb0ef41Sopenharmony_ci}
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_civoid VerifySpkac(const FunctionCallbackInfo<Value>& args) {
401cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
411cb0ef41Sopenharmony_ci  ArrayBufferOrViewContents<char> input(args[0]);
421cb0ef41Sopenharmony_ci  if (input.size() == 0)
431cb0ef41Sopenharmony_ci    return args.GetReturnValue().SetEmptyString();
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci  if (UNLIKELY(!input.CheckSizeInt32()))
461cb0ef41Sopenharmony_ci    return THROW_ERR_OUT_OF_RANGE(env, "spkac is too large");
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(VerifySpkac(input));
491cb0ef41Sopenharmony_ci}
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ciByteSource ExportPublicKey(Environment* env,
521cb0ef41Sopenharmony_ci                           const ArrayBufferOrViewContents<char>& input) {
531cb0ef41Sopenharmony_ci  BIOPointer bio(BIO_new(BIO_s_mem()));
541cb0ef41Sopenharmony_ci  if (!bio) return ByteSource();
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci  size_t length = input.size();
571cb0ef41Sopenharmony_ci#ifdef OPENSSL_IS_BORINGSSL
581cb0ef41Sopenharmony_ci  // OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
591cb0ef41Sopenharmony_ci  // while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
601cb0ef41Sopenharmony_ci  // As such, we trim those characters here for compatibility.
611cb0ef41Sopenharmony_ci  length = std::string(input.data()).find_last_not_of(" \n\r\t") + 1;
621cb0ef41Sopenharmony_ci#endif
631cb0ef41Sopenharmony_ci  NetscapeSPKIPointer spki(
641cb0ef41Sopenharmony_ci      NETSCAPE_SPKI_b64_decode(input.data(), length));
651cb0ef41Sopenharmony_ci  if (!spki) return ByteSource();
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  EVPKeyPointer pkey(NETSCAPE_SPKI_get_pubkey(spki.get()));
681cb0ef41Sopenharmony_ci  if (!pkey) return ByteSource();
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci  if (PEM_write_bio_PUBKEY(bio.get(), pkey.get()) <= 0) return ByteSource();
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci  return ByteSource::FromBIO(bio);
731cb0ef41Sopenharmony_ci}
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_civoid ExportPublicKey(const FunctionCallbackInfo<Value>& args) {
761cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci  ArrayBufferOrViewContents<char> input(args[0]);
791cb0ef41Sopenharmony_ci  if (input.size() == 0) return args.GetReturnValue().SetEmptyString();
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  if (UNLIKELY(!input.CheckSizeInt32()))
821cb0ef41Sopenharmony_ci    return THROW_ERR_OUT_OF_RANGE(env, "spkac is too large");
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci  ByteSource pkey = ExportPublicKey(env, input);
851cb0ef41Sopenharmony_ci  if (!pkey) return args.GetReturnValue().SetEmptyString();
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(pkey.ToBuffer(env).FromMaybe(Local<Value>()));
881cb0ef41Sopenharmony_ci}
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ciByteSource ExportChallenge(const ArrayBufferOrViewContents<char>& input) {
911cb0ef41Sopenharmony_ci  size_t length = input.size();
921cb0ef41Sopenharmony_ci#ifdef OPENSSL_IS_BORINGSSL
931cb0ef41Sopenharmony_ci  // OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
941cb0ef41Sopenharmony_ci  // while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
951cb0ef41Sopenharmony_ci  // As such, we trim those characters here for compatibility.
961cb0ef41Sopenharmony_ci  length = std::string(input.data()).find_last_not_of(" \n\r\t") + 1;
971cb0ef41Sopenharmony_ci#endif
981cb0ef41Sopenharmony_ci  NetscapeSPKIPointer sp(
991cb0ef41Sopenharmony_ci      NETSCAPE_SPKI_b64_decode(input.data(), length));
1001cb0ef41Sopenharmony_ci  if (!sp)
1011cb0ef41Sopenharmony_ci    return ByteSource();
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  unsigned char* buf = nullptr;
1041cb0ef41Sopenharmony_ci  int buf_size = ASN1_STRING_to_UTF8(&buf, sp->spkac->challenge);
1051cb0ef41Sopenharmony_ci  return (buf_size >= 0) ? ByteSource::Allocated(buf, buf_size) : ByteSource();
1061cb0ef41Sopenharmony_ci}
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_civoid ExportChallenge(const FunctionCallbackInfo<Value>& args) {
1091cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci  ArrayBufferOrViewContents<char> input(args[0]);
1121cb0ef41Sopenharmony_ci  if (input.size() == 0)
1131cb0ef41Sopenharmony_ci    return args.GetReturnValue().SetEmptyString();
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci  if (UNLIKELY(!input.CheckSizeInt32()))
1161cb0ef41Sopenharmony_ci    return THROW_ERR_OUT_OF_RANGE(env, "spkac is too large");
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci  ByteSource cert = ExportChallenge(input);
1191cb0ef41Sopenharmony_ci  if (!cert)
1201cb0ef41Sopenharmony_ci    return args.GetReturnValue().SetEmptyString();
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci  Local<Value> outString =
1231cb0ef41Sopenharmony_ci      Encode(env->isolate(), cert.data<char>(), cert.size(), BUFFER);
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(outString);
1261cb0ef41Sopenharmony_ci}
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_civoid Initialize(Environment* env, Local<Object> target) {
1291cb0ef41Sopenharmony_ci  Local<Context> context = env->context();
1301cb0ef41Sopenharmony_ci  SetMethodNoSideEffect(context, target, "certVerifySpkac", VerifySpkac);
1311cb0ef41Sopenharmony_ci  SetMethodNoSideEffect(
1321cb0ef41Sopenharmony_ci      context, target, "certExportPublicKey", ExportPublicKey);
1331cb0ef41Sopenharmony_ci  SetMethodNoSideEffect(
1341cb0ef41Sopenharmony_ci      context, target, "certExportChallenge", ExportChallenge);
1351cb0ef41Sopenharmony_ci}
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_civoid RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1381cb0ef41Sopenharmony_ci  registry->Register(VerifySpkac);
1391cb0ef41Sopenharmony_ci  registry->Register(ExportPublicKey);
1401cb0ef41Sopenharmony_ci  registry->Register(ExportChallenge);
1411cb0ef41Sopenharmony_ci}
1421cb0ef41Sopenharmony_ci}  // namespace SPKAC
1431cb0ef41Sopenharmony_ci}  // namespace crypto
1441cb0ef41Sopenharmony_ci}  // namespace node
145