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