22#include < algorithm>
33#include < cstring>
44#include " openssl/bn.h"
5+ #include " openssl/evp.h"
56#if OPENSSL_VERSION_MAJOR >= 3
67#include " openssl/provider.h"
78#endif
@@ -207,7 +208,7 @@ int NoPasswordCallback(char* buf, int size, int rwflag, void* u) {
207208}
208209
209210int PasswordCallback (char * buf, int size, int rwflag, void * u) {
210- const Buffer* passphrase = static_cast <const Buffer*>(u);
211+ auto passphrase = static_cast <const Buffer< char > *>(u);
211212 if (passphrase != nullptr ) {
212213 size_t buflen = static_cast <size_t >(size);
213214 size_t len = passphrase->len ;
@@ -220,4 +221,72 @@ int PasswordCallback(char* buf, int size, int rwflag, void* u) {
220221 return -1 ;
221222}
222223
224+ // ============================================================================
225+ // SPKAC
226+
227+ bool VerifySpkac (const char * input, size_t length) {
228+ #ifdef OPENSSL_IS_BORINGSSL
229+ // OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
230+ // while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
231+ // As such, we trim those characters here for compatibility.
232+ //
233+ // find_last_not_of can return npos, which is the maximum value of size_t.
234+ // The + 1 will force a roll-ver to 0, which is the correct value. in that
235+ // case.
236+ length = std::string_view (input, length).find_last_not_of (" \n\r\t " ) + 1 ;
237+ #endif
238+ NetscapeSPKIPointer spki (
239+ NETSCAPE_SPKI_b64_decode (input, length));
240+ if (!spki)
241+ return false ;
242+
243+ EVPKeyPointer pkey (X509_PUBKEY_get (spki->spkac ->pubkey ));
244+ return pkey ? NETSCAPE_SPKI_verify (spki.get (), pkey.get ()) > 0 : false ;
245+ }
246+
247+ BIOPointer ExportPublicKey (const char * input, size_t length) {
248+ BIOPointer bio (BIO_new (BIO_s_mem ()));
249+ if (!bio) return {};
250+
251+ #ifdef OPENSSL_IS_BORINGSSL
252+ // OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
253+ // while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
254+ // As such, we trim those characters here for compatibility.
255+ length = std::string_view (input, length).find_last_not_of (" \n\r\t " ) + 1 ;
256+ #endif
257+ NetscapeSPKIPointer spki (
258+ NETSCAPE_SPKI_b64_decode (input, length));
259+ if (!spki) return {};
260+
261+ EVPKeyPointer pkey (NETSCAPE_SPKI_get_pubkey (spki.get ()));
262+ if (!pkey) return {};
263+
264+ if (PEM_write_bio_PUBKEY (bio.get (), pkey.get ()) <= 0 ) return { };
265+
266+ return std::move (bio);
267+ }
268+
269+ Buffer<char > ExportChallenge (const char * input, size_t length) {
270+ #ifdef OPENSSL_IS_BORINGSSL
271+ // OpenSSL uses EVP_DecodeBlock, which explicitly removes trailing characters,
272+ // while BoringSSL uses EVP_DecodedLength and EVP_DecodeBase64, which do not.
273+ // As such, we trim those characters here for compatibility.
274+ length = std::string_view (input, length).find_last_not_of (" \n\r\t " ) + 1 ;
275+ #endif
276+ NetscapeSPKIPointer sp (
277+ NETSCAPE_SPKI_b64_decode (input, length));
278+ if (!sp) return {};
279+
280+ unsigned char * buf = nullptr ;
281+ int buf_size = ASN1_STRING_to_UTF8 (&buf, sp->spkac ->challenge );
282+ if (buf_size >= 0 ) {
283+ return {
284+ .data = reinterpret_cast <char *>(buf),
285+ .len = static_cast <size_t >(buf_size),
286+ };
287+ }
288+
289+ return {};
290+ }
291+
223292} // namespace ncrypto
0 commit comments