mbedtls_rsa_rsassa_pkcs1_v15_sign stack overflow - c++

I'm a hobbyist and this is my first dive into the world of C++ and embedded systems. I'm struggling a bit with mbedtls.
I'm trying to create a JWT to authenticate against google services. This involves sha256 hashing some base64 encoded json objects (header.claim) and then RSASSA-PKCS1-V1_5-SIGN signing that.
I seem to be ok up to the signing part. My understanding is I can parse the private key with mbedtls_pk_parse_key, and then use that mbedtls_pk_context with mbedtls_rsa_rsassa_pkcs1_v15_sign to sign the hash.
My issue is two fold, I'm not certain I am using mbedtls_rsa_rsassa_pkcs1_v15_sign correctly as the resulting base64 encoded signature comes out as the following in the console. While the encoded json objects are readable.
encodedHeader: ewoJImFsZyI6CSJSUzI1NiIsCgkidHlwIjoJIkpXVCIKfQ==
encodedSignature: ������������������������������������������������������...
Additionally right as this method returns, I get a stack overflow which I am not sure where it's coming from.
***ERROR*** A stack overflow in task main has been detected.
Backtrace:0x40081c0a:0x3ffb82700x40085a4d:0x3ffb8290 0x40088716:0x3ffb82b0 0x4008748f:0x3ffb8330 0x40085b4c:0x3ffb8350 0x40085afe:0x00000000 |<-CORRUPTED
ELF file SHA256: 4307a925ab3c9b48
Here is my code, any help would be greatly appreciated.
// Encode Header
unsigned char encodedHeader[92];
size_t encodedHeaderSize;
const unsigned char* headerRecast = reinterpret_cast<const unsigned char *>(cJSON_Print((const cJSON*) fHeader.toJSON()));
mbedtls_base64_encode(encodedHeader, 92, &encodedHeaderSize, headerRecast, strlen((const char *) headerRecast));
ESP_LOGI("encodedHeader", "%s", encodedHeader);
// Encode Claim
unsigned char encodedClaim[400];
size_t encodedClaimSize;
const unsigned char* claimRecast = reinterpret_cast<const unsigned char *>(cJSON_Print((const cJSON*) fClaim.toJSON()));
mbedtls_base64_encode(encodedClaim, 400, &encodedClaimSize, claimRecast, strlen((const char *) claimRecast));
ESP_LOGI("encodedClaim", "%s", encodedClaim);
// Concat the header and claim together
std::string headerStr((const char*) encodedHeader);
std::string claimStr((const char*) encodedClaim);
std::string auth = headerStr + "." + claimStr;
// Hash the header.claim
const unsigned char* resultRecast = reinterpret_cast<const unsigned char *>(auth.c_str());
mbedtls_sha256_context shaContext;
unsigned char outHash[32];
mbedtls_sha256_init(&shaContext);
mbedtls_sha256_starts(&shaContext, 0);
mbedtls_sha256_update(&shaContext, resultRecast, strlen((const char *) resultRecast));
mbedtls_sha256_finish(&shaContext, outHash);
mbedtls_sha256_free(&shaContext);
ESP_LOGI("outHash", "%s", outHash);
std::string shaStr;
for (int i=0; i<32; i++) {
char str[3];
sprintf(str, "%02x", (int)outHash[i]);
shaStr += reinterpret_cast<const char*>(str);
};
// pkcs1_v15_sign sign the hash
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_entropy_init( &entropy );
mbedtls_ctr_drbg_init( &ctr_drbg );
mbedtls_pk_context pkContext;
mbedtls_pk_init(&pkContext);
mbedtls_pk_parse_key(
&pkContext,
privateKey,
2000,
NULL,
0);
auto rsa = mbedtls_pk_rsa(pkContext);
unsigned char signature[2000];
int res = mbedtls_rsa_rsassa_pkcs1_v15_sign(rsa,
mbedtls_ctr_drbg_random, &ctr_drbg,
MBEDTLS_RSA_PRIVATE,
MBEDTLS_MD_SHA256,
32, reinterpret_cast<const unsigned char*>(shaStr.c_str()),
signature);
// Release Resources
mbedtls_rsa_free( rsa );
mbedtls_ctr_drbg_free( &ctr_drbg );
mbedtls_entropy_free( &entropy );
// Encode Signature
unsigned char encodedSignature[2000];
size_t encodedSignatureSize;
mbedtls_base64_encode(encodedSignature, 2000, &encodedSignatureSize, (const unsigned char*) signature, strlen((const char *) signature));
ESP_LOGI("encodedSignature", "%s", encodedSignature);
// Concat encoded hash.signature
std::string sig((const char*) encodedSignature);
std::string token = shaStr + "." + sig;
return token.c_str();
If it helps to understand my goal, here is a proof of concept I made in python
import requests
from Crypto.Signature import PKCS1_v1_5
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA256
from base64 import urlsafe_b64encode, urlsafe_b64decode
import json
import time
now = int(time.time())
header = {"alg": "RS256", "typ": "JWT"}
claim = {
"iss": "something",
"scope": "something",
"aud": "https://oauth2.googleapis.com/token",
"exp": now + 3600,
"iat": now
}
key = "{}.{}".format(urlsafe_b64encode(json.dumps(header).encode()).decode(), urlsafe_b64encode(json.dumps(claim).encode()).decode())
with open('key.json', 'r') as f:
creds = json.load(f)
keyPub = RSA.importKey(creds.get('private_key'))
h = SHA256.new(key.encode())
signer = PKCS1_v1_5.new(keyPub)
signature = signer.sign(h)
key = "{}.{}".format(key, urlsafe_b64encode(signature).decode())
print(key)

Related

PKCS#7 signing Base64 string and add signer info openssl

There is problem found while signing Nonce(Base64 string) with PKCS#7 using openssl
the problem is when i decode the signature the nonce is trimmed (get 4 char and the expected is 8 char)
Here is the code.
int main(int argc, char *argv[])
{
QString nonce = "Jd0VAO74";
QDateTime dateTime = QDateTime::fromString("2022-12-15T13:51:46Z", Qt::ISODateWithMs);
unsigned char*signature = signNonce(nonce, dateTime);
qDebug() << signature;
return 0;
}
unsigned char* signNonce(nonce, dateTime){
QContentInfo contentInfo = QContentInfo(QByteArray::fromBase64(nonce.toLatin1()));
auto signedCms = QSignedCms(contentInfo);
QOpenssl::QOpensslCertificate qOpensslCertificate(getCertificate());
QCmsSigner cmsSigner = QCmsSigner(qOpensslCertificate);
cmsSigner.setDigestType(QOpenssl::DigestType::SHA256);
cmsSigner.setPkcs9SigningTime(serverDateTime);
signedCms.computeSignatureNew(cmsSigner);
auto l_pSignedCms = PKCS7_PTR(PKCS7_new(),::PKCS7_free);
// set certificate and private key in a signer info.
QSignerInfo qsignerInfo;
PKCS7_SIGNER_INFO* signerInfo = PKCS7_SIGNER_INFO_new();
X509_PTR pX509 = cmsSigner.getCertificate().getCertificate();
EVP_PKEY_PTR pKey = cmsSigner.getCertificate().getPrivateKey();
const EVP_MD* pMD = EVP_sha256();
PKCS7_SIGNER_INFO_set(signerInfo, pX509.get(), pKey.get(), pMD);
// set signing time attribute.
ASN1_TIME* pSigningTime = ASN1_TIME_set(nullptr, cmsSigner.getPkcs9SigningTime().toTime_t());
PKCS7_add0_attrib_signing_time(signerInfo, pSigningTime);
qsignerInfo.setPkcs9SigningTime(cmsSigner.getPkcs9SigningTime());
// set message digest attribute.
QCryptographicHash::Algorithm algo = cmsSigner.getDigestType() == DigestType::SHA256
? QCryptographicHash::Algorithm::Sha256
: QCryptographicHash::Algorithm::Sha1;
QByteArray hash = QCryptographicHash::hash(m_ContentInfo.getContent(), algo);
const auto* pHash = reinterpret_cast<const unsigned char*>(hash.constData());
PKCS7_add1_attrib_digest(signerInfo, pHash, m_ContentInfo.getContent().length());
qsignerInfo.setDigestType(cmsSigner.getDigestType());
qsignerInfo.setHash(hash);
// set content type attribute.
PKCS7_add_attrib_content_type(signerInfo, OBJ_nid2obj(NID_pkcs7_data));
// sign signerinfo.
if(PKCS7_SIGNER_INFO_sign(signerInfo) <= 0) {
qCritical() << ERR_error_string(ERR_get_error(), nullptr);
return;
}
// add signer info to cms.
PKCS7_add_signer(l_pSignedCms.get(), signerInfo);
// set data to cms.
// set certificate to cms.
PKCS7_add_certificate(l_pSignedCms.get(), pX509.get());
// set certificate chain
for(const QOpensslCertificate& cert : cmsSigner.getCertificate().getCertificateChain()) {
if(!cert.isSelfSigned())
PKCS7_add_certificate(l_pSignedCms.get(), cert.getCertificate().get());
}
// set content data.
BIO_PTR pContent = BIO_PTR(BIO_new(BIO_s_mem()), ::BIO_free);
BIO_puts(pContent.get(), m_ContentInfo.getContent().constData());
m_pSignedCms = PKCS7_PTR(
PKCS7_sign(pX509.get(), pKey.get(), nullptr, pContent.get(), 0),
::PKCS7_free);
unsigned char* pSignedValue = nullptr;
int result = i2d_PKCS7(m_pSignedCms.get(), &pSignedValue);
return pSignedValue ;
}
after decodeing online decoder the signature, we found nonce in hex 0x25 DD 15
the nonce only contains 4 char Jd0V
any one has a clue ?
I try to figure out why the decoded signature only contains 4 char not 8

error:0407008A:rsa routines:RSA_padding_check_PKCS1_type_1:invalid padding openssl C++

I am trying to verify a signature using OpenSSL in C++. The code is below:
bool verifySignature(QString updateInfo_file_signature, QString uInfo_file_hash) {
RSA *rsa = NULL;
BIO *keybio;
FILE *file = fopen("pubkey.pem", "rb");
fseek(file, 0, SEEK_END);
long fsize = ftell(file);
fseek(file, 0, SEEK_SET);
char *key = (char*)malloc(fsize + 1);
fread(key, 1, fsize, file);
fclose(file);
keybio = BIO_new_mem_buf((void*)key, -1);
if (keybio==NULL)
return 0;
rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL);
if(rsa == NULL)
return 0;
int rsa_size = RSA_size(rsa);
// vars
const char* sign_file_hash = uInfo_file_hash.toStdString().c_str();
unsigned char* u_file_hash = (unsigned char*) uInfo_file_hash.toLocal8Bit().data();
const char* sign_file_sig = updateInfo_file_signature.toStdString().c_str();
unsigned char* u_file_sig = (unsigned char*) updateInfo_file_signature.toLocal8Bit().data();
int hash_size = strlen(sign_file_hash);
int sig_size = strlen(sign_file_sig);
int res = RSA_verify(NID_sha1, u_file_hash, 16, u_file_sig, rsa_size, rsa);
printError();
return 0;
}
But I am getting this error:
error:0407008A:rsa routines:RSA_padding_check_PKCS1_type_1:invalid padding
Here is my public key:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwOEGwubWUh8jRdSogJMm
q3MiwXAcPVWa9DJxVY0tEtFjclFrV63QjOKdbpow1dhl7suHeDrWx1XRoLWeKbpt
0MHiXInH3BMV9iRH83RX3FPhrenFND4OZenqqfXuh2n0zZrdyZGqlum73wx6YoRs
3Es0sYYQ03qKL6BhX90w1d1fS0/KBkMkp+jSXN9IhcVAzRCrceiZbmiOOwPLxIFL
s75MywAFAu5E5qYi12T+8Ou08UcvmkBWkHUt0m2gtWWyhfO5r918thH1ThIs7cRA
/BG8/Xq4ycVOeMSBKc+KcKMofWNpLZRmnzarS9reTv0bKr7/Mevqz8dXmACRzyMU
uwIDAQAB
-----END PUBLIC KEY-----
Here is file Signature (updateInfo_file_signature::QString): saKBgdDIS/rsb7Uazr6zWMYsGLU8CYN6YaUZh5nyNjo7PCImCNtXBV+4TuFnKV6obz1rdqqUX+0Lwan8gquqQzYJFFQZFVexHSEyzxPZXYLmyFU35Gbko/iSGlkg8F/DVCSPsSttlhhQJjjHCbMB9i+DgzFMCDYVhd9lrtuEVDauXDtuEZi5MtEbyA1G3i5LT9H6Hr7XUTQN7QAnbHxCdtPc81FHO9+WEdu/lDdmT+rfWKO1REEeOVd/0Pf/pGTCVdnVsCA+S3UD310Ft13UB8KyQ5xN/KrncUFibaKzzKShR2/pXPHWWhkP5Ceku4cJOiV7YY9+ZUPMV7rfJq9KDw==
Here is computed File hash in sha256 (uInfo_file_hash::QString):
712b6ec279d490ede7454f34d1f6ffff
I have tried cat -v pubkey.pem but still it seems legit.
I've been struggling with it for days, please do some magic and help me out.
P.S: Please excuse any memory leaks or unused variables because this is a code snippet and they are taken care of later.
I think the problem is that you are storing a pointer to a temporary variable that has gone out of scope by the time you use it:
const char* sign_file_hash = uInfo_file_hash.toStdString().c_str();
The Qstring::toStdString() method return a std::string by value, but you are not storing the std::string anywhere. Instead, you get the pointer to its contents using .c_str(), but after this line has executed, the std::string no longer exist. The same happens in this line:
unsigned char* u_file_hash = (unsigned char*) uInfo_file_hash.toLocal8Bit().data();
The solution is to store the temporary in a variable first:
QByteArray u_file_hash = uInfo_file_hash.toLocal8Bit();
And apply .data() as late as possible:
int res = RSA_verify(NID_sha1, u_file_hash.data(), 16, u_file_sig.data(), rsa_size, rsa);
I also see that sign_file_hash, sign_file_sig, hash_size and sig_size are not actually used for anything.

Decrypt with Public Key in C/C++

So I'm currently working on a web service for Amazon Alexa.
For their request authentication, I'm downloading and validating a certificate. Afterwards I shall decrypt a signature with the certificate's public key.
Now I've tried some things with Poco and OpenSSL, never getting a fitting result.
One example as a try for OpenSSL:
void decryptWithPublicKey(const std::string & input, const std::shared_ptr<Poco::Crypto::X509Certificate> & cert, std::string & buffer)
{
RSA * decryptor = Poco::Crypto::RSAKey(*key).impl()->getRSA();
const unsigned char * from = (const unsigned char*) input.c_str();
unsigned char* to = new unsigned char[ RSA_size(decryptor)-12 ];;
int result = RSA_public_decrypt((int) input.length(), from, to, decryptor, RSA_PKCS1_PADDING);
if(result == -1)
{
// print error
}
else
{
buffer.append((char*) to);
}
delete from;
delete[] to;
}
Output is always sth like "0!0 +\n PuTTYPuTTY"
Anyone has any experience with that?

RSA_sign and RSA_verify varied behavior

I have a sample signature generator in C which will create a hash message <count:mac-addr> and generate a signature.
When I use char *message = "120:08:00:27:7c:b6:18";
and sign, the signature is verified successfully.
But when I use
char * generate_hash()
{
xmlDoc *document;
xmlNode *root, *first_child, *node;
char *filename;
char *ap_count;
char *ap_mac_address;
char *message;
filename = "/license.xml";
document = xmlReadFile(filename, NULL, 0);
root = xmlDocGetRootElement(document);
first_child = root->children;
for (node = first_child; node; node = node->next) {
if ( strcmp((char*)node->name, "ap_count") == 0 ) {
ap_count = (char*)xmlNodeGetContent(node);
}
if ( strcmp((char*)node->name, "ap_mac_address") == 0 ){
ap_mac_address = (char*)xmlNodeGetContent(node);
}
}
message = (char *) malloc(strlen(ap_count)+ strlen(ap_mac_address) +1 );
memset(message,0x0,(1 + strlen(ap_count)+ strlen(ap_mac_address)));
strcpy(message,ap_count);
strcat(message,":");
strcat(message,ap_mac_address);
printf(" %d \n", (1 + strlen(ap_count)+ strlen(ap_mac_address)));
return message;
}
--- while verifying,
char* message;
message = generate_hash();
I am using the below function call to generate the signature in both the cases.
if(RSA_sign(NID_sha256, (unsigned char*) message, strlen(message),
signature, &slen, private_key) != 1) {
ERR_print_errors_fp(stdout);
return 1;
}
The signature verification fails with this above procedure. Not sure what I am doing wrong here.
Below is the call I am using to verify the same.
verified = RSA_verify(NID_sha256, (unsigned char*) message,
strlen(message), sign, file_len, public_key);
verified = RSA_verify(NID_sha256, (unsigned char*) message,
strlen(message), sign, file_len, public_key);
The signature could have an embedded NULL. Do not treat it like string data, and don't use strlen on it.
You have to manage a pointer and an explicit length.
The description of RSA_verify tells following:
RSA_verify() verifies that the signature sigbuf of size siglen matches
a given message digest m of size m_len. type denotes the message
digest algorithm that was used to generate the signature. rsa is the
signer's public key.
So, using RSA_verify with original message is not correct: message digest should be used instead.

HMAC on Mountain lion OSX 10.8.3 EXC_CRASH

Looking for a bit of help using OpenSSL's HMAC function. Currently this function is failing on the HMAC call. ONLY for OSX. Both linux and windows os's are working okay.
QString tradingDialog::HMAC_SHA512_SIGNER(QString UrlToSign, QString Secret){
QString retval = "";
QByteArray byteArray = UrlToSign.toUtf8();
const char* URL = byteArray.constData();
QByteArray byteArrayB = Secret.toUtf8();
const char* Secretkey = byteArrayB.constData();
const EVP_MD *md = EVP_sha512();
unsigned char* digest = NULL;
// Be careful of the length of string with the choosen hash engine. SHA1 produces a 20-byte hash value which rendered as 40 characters.
// Change the length accordingly with your choosen hash engine
char mdString[129] = { 0 };
// Using sha512 hash engine here.
digest = HMAC(md, Secretkey, strlen( Secretkey), (unsigned char*) URL, strlen( URL), NULL, NULL);
for(int i = 0; i < 64; i++){
sprintf(&mdString[i*2], "%02x", (unsigned int)digest[i]);
}
retval = mdString;
return retval;
}
You don't say what the problem is on osx, but it looks like you're not nul terminating mdString, so try changing it to
char mdString[129] = { 0 };
The crashlog you linked to shows that your app is aborting because the stack has been corrupted (I assume this happens on exit).
I would say the final sprintf is causing this, as it is adding a nul byte after the end of your mdString array. Try the above modification and see if that helps.
This ought to crash on all platforms, but I guess you got "lucky".