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