Skip to content
File

Blob: src/workerd/api/crypto/spkac.c++

2.8 KB
1#include "spkac.h"
2 
3#include "impl.h"
4 
5#include <workerd/io/io-context.h>
6#include <workerd/jsg/jsg.h>
7 
8#include <ncrypto.h>
9 
10namespace workerd::api {
11 
12bool verifySpkac(kj::ArrayPtr<const kj::byte> input) {
13 // So, this is fun. SPKAC uses MD5 as the digest algorithm. This is a problem because
14 // using MD5 for signature verification is not allowed in FIPS mode, which means that
15 // although we have a working implementation here, the result of this call is always
16 // going to be false even if the input signature is correct. So this is a bit of a dead
17 // end that isn't going to be super useful. Fortunately tho the exportPublicKey and
18 // exportChallenge functions both work correctly and are useful. Unfortunately, this
19 // likely means users would need to implement their own verification, which sucks.
20 //
21 // Alternatively we could choose to implement our own version of the validation that
22 // bypasses BoringSSL's FIPS configuration. For now tho, this does end up matching
23 // Node.js' behavior when FIPS is enabled so I guess that's something.
24 KJ_IF_SOME(ioContext, IoContext::tryCurrent()) {
25 ioContext.logWarningOnce(
26 "The verifySpkac function is currently of limited value in workers because "
27 "the SPKAC signature verification uses MD5, which is not supported in FIPS mode. "
28 "All workers run in FIPS mode. Accordingly, this method will currently always "
29 "return false even if the SPKAC signature is valid. This is a known limitation.");
30 }
31 
32 // Works around a bug in ncrypto...
33 auto pos = std::string_view(input.asChars().begin(), input.size()).find_last_not_of(" \n\r\t");
34 if (pos == std::string_view::npos) {
35 return false;
36 }
37 
38 return ncrypto::VerifySpkac(ToNcryptoBuffer(input.asChars()));
39}
40 
41kj::Maybe<jsg::JsUint8Array> exportPublicKey(jsg::Lock& js, kj::ArrayPtr<const kj::byte> input) {
42 // Works around a bug in ncrypto...
43 auto pos = std::string_view(input.asChars().begin(), input.size()).find_last_not_of(" \n\r\t");
44 if (pos == std::string_view::npos) {
45 return kj::none;
46 }
47 
48 if (auto bio = ncrypto::ExportPublicKey(ToNcryptoBuffer(input.asChars()))) {
49 BUF_MEM* bptr = bio;
50 auto buf = jsg::JsUint8Array::create(js, bptr->length);
51 auto aptr = kj::arrayPtr(bptr->data, bptr->length);
52 buf.asArrayPtr<char>().copyFrom(aptr);
53 return buf;
54 }
55 return kj::none;
56}
57 
58kj::Maybe<jsg::JsUint8Array> exportChallenge(jsg::Lock& js, kj::ArrayPtr<const kj::byte> input) {
59 
60 // Works around a bug in ncrypto...
61 auto pos = std::string_view(input.asChars().begin(), input.size()).find_last_not_of(" \n\r\t");
62 if (pos == std::string_view::npos) {
63 return kj::none;
64 }
65 
66 if (auto dp = ncrypto::ExportChallenge(ToNcryptoBuffer(input.asChars()))) {
67 auto src = kj::arrayPtr(dp.get<kj::byte>(), dp.size());
68 return jsg::JsUint8Array::create(js, src);
69 }
70 return kj::none;
71}
72} // namespace workerd::api