GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_spkac.cc Lines: 64 67 95.5 %
Date: 2022-06-12 04:16:28 Branches: 25 32 78.1 %

Line Branch Exec Source
1
#include "crypto/crypto_spkac.h"
2
#include "crypto/crypto_common.h"
3
#include "crypto/crypto_util.h"
4
#include "env-inl.h"
5
#include "memory_tracker-inl.h"
6
#include "node.h"
7
#include "v8.h"
8
9
namespace node {
10
11
using v8::FunctionCallbackInfo;
12
using v8::Local;
13
using v8::Object;
14
using v8::Value;
15
16
namespace crypto {
17
namespace SPKAC {
18
10
bool VerifySpkac(const ArrayBufferOrViewContents<char>& input) {
19
10
  size_t length = input.size();
20
#ifdef OPENSSL_IS_BORINGSSL
21
  // OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
22
  // while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
23
  // As such, we trim those characters here for compatibility.
24
  length = std::string(input.data()).find_last_not_of(" \n\r\t") + 1;
25
#endif
26
  NetscapeSPKIPointer spki(
27
20
      NETSCAPE_SPKI_b64_decode(input.data(), length));
28
10
  if (!spki)
29
2
    return false;
30
31
16
  EVPKeyPointer pkey(X509_PUBKEY_get(spki->spkac->pubkey));
32
8
  if (!pkey)
33
    return false;
34
35
8
  return NETSCAPE_SPKI_verify(spki.get(), pkey.get()) > 0;
36
}
37
38
11
void VerifySpkac(const FunctionCallbackInfo<Value>& args) {
39
11
  Environment* env = Environment::GetCurrent(args);
40
11
  ArrayBufferOrViewContents<char> input(args[0]);
41
11
  if (input.size() == 0)
42
    return args.GetReturnValue().SetEmptyString();
43
44
11
  if (UNLIKELY(!input.CheckSizeInt32()))
45
1
    return THROW_ERR_OUT_OF_RANGE(env, "spkac is too large");
46
47
20
  args.GetReturnValue().Set(VerifySpkac(input));
48
}
49
50
4
ByteSource ExportPublicKey(Environment* env,
51
                           const ArrayBufferOrViewContents<char>& input) {
52
8
  BIOPointer bio(BIO_new(BIO_s_mem()));
53
4
  if (!bio) return ByteSource();
54
55
4
  size_t length = input.size();
56
#ifdef OPENSSL_IS_BORINGSSL
57
  // OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
58
  // while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
59
  // As such, we trim those characters here for compatibility.
60
  length = std::string(input.data()).find_last_not_of(" \n\r\t") + 1;
61
#endif
62
  NetscapeSPKIPointer spki(
63
8
      NETSCAPE_SPKI_b64_decode(input.data(), length));
64
4
  if (!spki) return ByteSource();
65
66
4
  EVPKeyPointer pkey(NETSCAPE_SPKI_get_pubkey(spki.get()));
67
2
  if (!pkey) return ByteSource();
68
69
2
  if (PEM_write_bio_PUBKEY(bio.get(), pkey.get()) <= 0) return ByteSource();
70
71
2
  return ByteSource::FromBIO(bio);
72
}
73
74
5
void ExportPublicKey(const FunctionCallbackInfo<Value>& args) {
75
5
  Environment* env = Environment::GetCurrent(args);
76
77
5
  ArrayBufferOrViewContents<char> input(args[0]);
78
5
  if (input.size() == 0) return args.GetReturnValue().SetEmptyString();
79
80
5
  if (UNLIKELY(!input.CheckSizeInt32()))
81
1
    return THROW_ERR_OUT_OF_RANGE(env, "spkac is too large");
82
83
4
  ByteSource pkey = ExportPublicKey(env, input);
84
8
  if (!pkey) return args.GetReturnValue().SetEmptyString();
85
86
6
  args.GetReturnValue().Set(pkey.ToBuffer(env).FromMaybe(Local<Value>()));
87
}
88
89
4
ByteSource ExportChallenge(const ArrayBufferOrViewContents<char>& input) {
90
4
  size_t length = input.size();
91
#ifdef OPENSSL_IS_BORINGSSL
92
  // OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
93
  // while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
94
  // As such, we trim those characters here for compatibility.
95
  length = std::string(input.data()).find_last_not_of(" \n\r\t") + 1;
96
#endif
97
  NetscapeSPKIPointer sp(
98
8
      NETSCAPE_SPKI_b64_decode(input.data(), length));
99
4
  if (!sp)
100
2
    return ByteSource();
101
102
2
  char* buf = nullptr;
103
2
  ASN1_STRING_to_UTF8(
104
    reinterpret_cast<unsigned char**>(&buf),
105
2
    sp->spkac->challenge);
106
107
2
  return ByteSource::Allocated(buf, strlen(buf));
108
}
109
110
5
void ExportChallenge(const FunctionCallbackInfo<Value>& args) {
111
5
  Environment* env = Environment::GetCurrent(args);
112
113
5
  ArrayBufferOrViewContents<char> input(args[0]);
114
5
  if (input.size() == 0)
115
    return args.GetReturnValue().SetEmptyString();
116
117
5
  if (UNLIKELY(!input.CheckSizeInt32()))
118
1
    return THROW_ERR_OUT_OF_RANGE(env, "spkac is too large");
119
120
4
  ByteSource cert = ExportChallenge(input);
121
4
  if (!cert)
122
4
    return args.GetReturnValue().SetEmptyString();
123
124
  Local<Value> outString =
125
2
      Encode(env->isolate(), cert.get(), cert.size(), BUFFER);
126
127
4
  args.GetReturnValue().Set(outString);
128
}
129
130
854
void Initialize(Environment* env, Local<Object> target) {
131
854
  env->SetMethodNoSideEffect(target, "certVerifySpkac", VerifySpkac);
132
854
  env->SetMethodNoSideEffect(target, "certExportPublicKey", ExportPublicKey);
133
854
  env->SetMethodNoSideEffect(target, "certExportChallenge", ExportChallenge);
134
854
}
135
136
5205
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
137
5205
  registry->Register(VerifySpkac);
138
5205
  registry->Register(ExportPublicKey);
139
5205
  registry->Register(ExportChallenge);
140
5205
}
141
}  // namespace SPKAC
142
}  // namespace crypto
143
}  // namespace node