GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_spkac.cc Lines: 63 66 95.5 %
Date: 2022-07-30 04:16:22 Branches: 26 34 76.5 %

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
  unsigned char* buf = nullptr;
103
2
  int buf_size = ASN1_STRING_to_UTF8(&buf, sp->spkac->challenge);
104
2
  return (buf_size >= 0) ? ByteSource::Allocated(buf, buf_size) : ByteSource();
105
}
106
107
5
void ExportChallenge(const FunctionCallbackInfo<Value>& args) {
108
5
  Environment* env = Environment::GetCurrent(args);
109
110
5
  ArrayBufferOrViewContents<char> input(args[0]);
111
5
  if (input.size() == 0)
112
    return args.GetReturnValue().SetEmptyString();
113
114
5
  if (UNLIKELY(!input.CheckSizeInt32()))
115
1
    return THROW_ERR_OUT_OF_RANGE(env, "spkac is too large");
116
117
4
  ByteSource cert = ExportChallenge(input);
118
4
  if (!cert)
119
4
    return args.GetReturnValue().SetEmptyString();
120
121
  Local<Value> outString =
122
2
      Encode(env->isolate(), cert.data<char>(), cert.size(), BUFFER);
123
124
4
  args.GetReturnValue().Set(outString);
125
}
126
127
1306
void Initialize(Environment* env, Local<Object> target) {
128
1306
  env->SetMethodNoSideEffect(target, "certVerifySpkac", VerifySpkac);
129
1306
  env->SetMethodNoSideEffect(target, "certExportPublicKey", ExportPublicKey);
130
1306
  env->SetMethodNoSideEffect(target, "certExportChallenge", ExportChallenge);
131
1306
}
132
133
5286
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
134
5286
  registry->Register(VerifySpkac);
135
5286
  registry->Register(ExportPublicKey);
136
5286
  registry->Register(ExportChallenge);
137
5286
}
138
}  // namespace SPKAC
139
}  // namespace crypto
140
}  // namespace node