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

Loading RSA private key file containing OID "rsaPSS" throws BERDecode error #1181

Open
luckyPandaBear opened this issue Dec 7, 2022 · 1 comment

Comments

@luckyPandaBear
Copy link

luckyPandaBear commented Dec 7, 2022

RSAPrivKeys.zip

When importing RSA private key files as attached, Crypto++ seems to support structures containing the OID for "rsaEncryption" (1 2 840 113549 1 1 1) only. Whenever a private key file is presented indicating the OID for "rsaPSS" (1 2 840 113549 1 1 10), the Load() function throws a "BERDecode error" exception.

Sample code:

CryptoPP::InvertibleRSAFunction rsa;
CryptoPP::FileSource fs("privKey.pkcs8", true);
rsa.Load(fs);

The same behaviour applies to:

rsa.BERDecode(fs);

Why is it not possible to import key files with "rsaPSS" OID included?

@noloader
Copy link
Collaborator

noloader commented Oct 1, 2023

The problems is here in rsa.cpp:

OID RSAFunction::GetAlgorithmID() const
{
	return ASN1::rsaEncryption();
}

rsaEncryption is OID 1.2.840.113549.1.1.1. It causes the exception in PKCS8PrivateKey::BERDecode when BERDecodeAndCheck is called.

I think the quickest workaround is to add a RSA_PSS, which uses the expected OID:

$ git diff
diff --git a/rsa.h b/rsa.h
index 3f2312ee..330fc33f 100644
--- a/rsa.h
+++ b/rsa.h
@@ -155,6 +155,26 @@ public:
        Integer PreimageBound() const {return ++(m_n>>1);}
 };
 
+/// \brief RSA trapdoor function using the public key
+/// \since Crypto++ 1.0
+class CRYPTOPP_DLL RSAFunction_PSS : public RSAFunction
+{
+public:
+       OID GetAlgorithmID() const {
+               return ASN1::rsassa_pss();
+       }
+};
+
+/// \brief RSA trapdoor function using the private key
+/// \since Crypto++ 1.0
+class CRYPTOPP_DLL InvertibleRSAFunction_PSS : public InvertibleRSAFunction
+{
+public:
+       OID GetAlgorithmID() const {
+               return ASN1::rsassa_pss();
+       }
+};
+
 /// \brief RSA algorithm
 /// \since Crypto++ 1.0
 struct CRYPTOPP_DLL RSA
@@ -164,6 +184,15 @@ struct CRYPTOPP_DLL RSA
        typedef InvertibleRSAFunction PrivateKey;
 };
 
+/// \brief RSA algorithm
+/// \since Crypto++ 1.0
+struct CRYPTOPP_DLL RSA_PSS
+{
+       CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "RSA";}
+       typedef RSAFunction_PSS PublicKey;
+       typedef InvertibleRSAFunction_PSS PrivateKey;
+};
+
 /// \brief RSA encryption algorithm
 /// \tparam STANDARD signature standard
 /// \sa <a href="http://www.weidai.com/scan-mirror/ca.html#RSA">RSA cryptosystem</a>

And then in your program:

RSA_PSS::PrivateKey rsa;
FileSource fs("privKey.pkcs8", true);
rsa.Load(fs);

A new RSA_PSS class is not the only way to solve the problem. Here is another way, which is mostly a copy/paste/modify of PKCS8PrivateKey::BERDecode.

#include "config.h"
#include "files.h"
#include "oids.h"
#include "asn.h"
#include "rsa.h"

using namespace CryptoPP;

bool BERDecodeAlgorithmParameters(BufferedTransformation &bt)
{
	BERDecodeNull(bt);
	return false;
}

RSA::PrivateKey LoadAndCheck(BufferedTransformation& bt, const OID& oid /*expected*/)
{
	BERSequenceDecoder privateKeyInfo(bt);
		word32 version;
		BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 0);	// check version

		BERSequenceDecoder algorithm(privateKeyInfo);
			oid.BERDecodeAndCheck(algorithm);
			bool parametersPresent = algorithm.EndReached() ? false : BERDecodeAlgorithmParameters(algorithm);
		algorithm.MessageEnd();

		BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING);
			RSA::PrivateKey key;
			key.BERDecodePrivateKey(octetString, parametersPresent, octetString.RemainingLength());
		octetString.MessageEnd();

	privateKeyInfo.MessageEnd();

	return key;
}

int main(int argc, char* argv[])
{
    FileSource fs("RSAPrivPSS.pkcs8", true);
    RSA::PrivateKey key = LoadAndCheck(fs, ASN1::rsassa_pss());
    return 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants