Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crypto: deduplicate public key parsing #22553

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 51 additions & 54 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3648,6 +3648,45 @@ void Sign::SignFinal(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(rc);
}

enum ParsePublicKeyResult {
kParsePublicOk,
kParsePublicNotRecognized,
kParsePublicFailed
};

static ParsePublicKeyResult ParsePublicKey(EVPKeyPointer* pkey,
const char* key_pem,
int key_pem_len) {
BIOPointer bp(BIO_new_mem_buf(const_cast<char*>(key_pem), key_pem_len));
if (!bp)
return kParsePublicFailed;

// Check if this is a PKCS#8 or RSA public key before trying as X.509.
if (strncmp(key_pem, PUBLIC_KEY_PFX, PUBLIC_KEY_PFX_LEN) == 0) {
pkey->reset(
PEM_read_bio_PUBKEY(bp.get(), nullptr, NoPasswordCallback, nullptr));
} else if (strncmp(key_pem, PUBRSA_KEY_PFX, PUBRSA_KEY_PFX_LEN) == 0) {
RSAPointer rsa(PEM_read_bio_RSAPublicKey(
bp.get(), nullptr, PasswordCallback, nullptr));
if (rsa) {
pkey->reset(EVP_PKEY_new());
if (*pkey)
EVP_PKEY_set1_RSA(pkey->get(), rsa.get());
}
} else if (strncmp(key_pem, CERTIFICATE_PFX, CERTIFICATE_PFX_LEN) == 0) {
// X.509 fallback
X509Pointer x509(PEM_read_bio_X509(
bp.get(), nullptr, NoPasswordCallback, nullptr));
if (!x509)
return kParsePublicFailed;

pkey->reset(X509_get_pubkey(x509.get()));
} else {
return kParsePublicNotRecognized;
}

return *pkey ? kParsePublicOk : kParsePublicFailed;
}

void Verify::Initialize(Environment* env, v8::Local<Object> target) {
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
Expand Down Expand Up @@ -3708,34 +3747,7 @@ SignBase::Error Verify::VerifyFinal(const char* key_pem,
*verify_result = false;
EVPMDPointer mdctx = std::move(mdctx_);

BIOPointer bp(BIO_new_mem_buf(const_cast<char*>(key_pem), key_pem_len));
if (!bp)
return kSignPublicKey;

// Check if this is a PKCS#8 or RSA public key before trying as X.509.
// Split this out into a separate function once we have more than one
// consumer of public keys.
if (strncmp(key_pem, PUBLIC_KEY_PFX, PUBLIC_KEY_PFX_LEN) == 0) {
pkey.reset(
PEM_read_bio_PUBKEY(bp.get(), nullptr, NoPasswordCallback, nullptr));
} else if (strncmp(key_pem, PUBRSA_KEY_PFX, PUBRSA_KEY_PFX_LEN) == 0) {
RSAPointer rsa(PEM_read_bio_RSAPublicKey(
bp.get(), nullptr, PasswordCallback, nullptr));
if (rsa) {
pkey.reset(EVP_PKEY_new());
if (pkey)
EVP_PKEY_set1_RSA(pkey.get(), rsa.get());
}
} else {
// X.509 fallback
X509Pointer x509(PEM_read_bio_X509(
bp.get(), nullptr, NoPasswordCallback, nullptr));
if (!x509)
return kSignPublicKey;

pkey.reset(X509_get_pubkey(x509.get()));
}
if (!pkey)
if (ParsePublicKey(&pkey, key_pem, key_pem_len) != kParsePublicOk)
return kSignPublicKey;

if (!EVP_DigestFinal_ex(mdctx.get(), m, &m_len))
Expand Down Expand Up @@ -3805,40 +3817,25 @@ bool PublicKeyCipher::Cipher(const char* key_pem,
size_t* out_len) {
EVPKeyPointer pkey;

BIOPointer bp(BIO_new_mem_buf(const_cast<char*>(key_pem), key_pem_len));
if (!bp)
return false;

// Check if this is a PKCS#8 or RSA public key before trying as X.509 and
// private key.
if (operation == kPublic &&
strncmp(key_pem, PUBLIC_KEY_PFX, PUBLIC_KEY_PFX_LEN) == 0) {
pkey.reset(PEM_read_bio_PUBKEY(bp.get(), nullptr, nullptr, nullptr));
} else if (operation == kPublic &&
strncmp(key_pem, PUBRSA_KEY_PFX, PUBRSA_KEY_PFX_LEN) == 0) {
RSAPointer rsa(
PEM_read_bio_RSAPublicKey(bp.get(), nullptr, nullptr, nullptr));
if (rsa) {
pkey.reset(EVP_PKEY_new());
if (pkey)
EVP_PKEY_set1_RSA(pkey.get(), rsa.get());
}
} else if (operation == kPublic &&
strncmp(key_pem, CERTIFICATE_PFX, CERTIFICATE_PFX_LEN) == 0) {
X509Pointer x509(
PEM_read_bio_X509(bp.get(), nullptr, NoPasswordCallback, nullptr));
if (!x509)
if (operation == kPublic) {
ParsePublicKeyResult pkeyres = ParsePublicKey(&pkey, key_pem, key_pem_len);
if (pkeyres == kParsePublicFailed)
return false;
}
if (!pkey) {
// Private key fallback.
BIOPointer bp(BIO_new_mem_buf(const_cast<char*>(key_pem), key_pem_len));
if (!bp)
return false;

pkey.reset(X509_get_pubkey(x509.get()));
} else {
pkey.reset(PEM_read_bio_PrivateKey(bp.get(),
nullptr,
PasswordCallback,
const_cast<char*>(passphrase)));
if (!pkey)
return false;
}
if (!pkey)
return false;

EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
if (!ctx)
Expand Down