Certificate Verify, "error:068000C7:asn1 encoding routines::unknown signature algorithm" - c++

I would like to create a certificate with ECC. I am using ecdsa_with_SHA3-512 as signature algorithm.
I can succesfully sign the certificate as below.
auto message_digest = EVP_MD_fetch(nullptr,"SHA3-512", nullptr);
if (!message_digest) {
...
}
if(auto ssize = X509_sign(cert,pkey,message_digest)){
...
}
But I can`t verify the signature as below.
auto result = X509_verify(cert,pkey);
if (result <= 0) {
printf("[verify is failed : %d]\n",result);
}
auto errCode = ERR_peek_last_error();
auto errBuf = new char[256];
ERR_error_string(errCode,errBuf);
std::cout << errBuf << "\n";
I get [verify result : -1] error:068000C7:asn1 encoding routines::unknown signature algorithm error message.
I am checking tbs signature and certificate signature objects, they are equal.
if(X509_ALGOR_cmp(signatureAlg, tbsSignature)) {
...
}
Below is tbs signature object fields.
tbs signature ln : ecdsa_with_SHA3-512
tbs signature sn : id-ecdsa-with-sha3-512
tbs signature nid : 1115
As I understand X509_verify() checks the signature algorithm nid from
nid_triple sigoid_srt[] array. And cant find NID_ecdsa_with_SHA3_512 algorithm nid. Because of this, it gives unkown algorithm error.
I am new to cryptography and openssl, What I am missing.
Edit : This hash/signature algorithm combination is not
supported by any of the current releases by itself.

Related

CryptoPP::ed25519::Verifier shows different result from libsignal

I'm trying to implement curve25519 verification with CryptoPP. I tried the libsignal library first, witch shows correct result. Then I tried the same data with CryptoPP, but shows wrong result.
Here is the code using libsignal to verify a signature:
string pub = str2hex("0504f05568cc7a16fa9b4bc1c9d9294a80b7727e349365f855031a180bf0f80910");
ec_public_key* pub_key;
curve_decode_point(&pub_key, (uint8_t*)pub.data(), pub.size(), 0);
string message = str2hex("05f1fd491d63f1860bdaf3f9b0eb46c2494b7f184a32d9e6c859a421ad284f4307");
string signature = str2hex("5e525df3360ea62281efe8fb9e183521105bb3d9ba8ad43be9fac9d87dd216a6ea9e64099f6f05fbcd6e5a39ab239aad8c1e03d27a1378e4bcbf8937eac4300a");
int ret = curve_verify_signature(
pub_key,
(uint8_t*)message.data(), message.size(),
(uint8_t*)signature.data(), signature.size()
);
cout << "ret: " << ret << endl; // shows 1 (correct)
The result is 1 which means corrent. Please note libsignal requires the pub_key begin with a byte 0x05(key-type), not for CryptoPP here.
The code using CryptoPP:
string pub = str2hex("04f05568cc7a16fa9b4bc1c9d9294a80b7727e349365f855031a180bf0f80910");
string message = str2hex("05f1fd491d63f1860bdaf3f9b0eb46c2494b7f184a32d9e6c859a421ad284f4307");
string signature = str2hex("5e525df3360ea62281efe8fb9e183521105bb3d9ba8ad43be9fac9d87dd216a6ea9e64099f6f05fbcd6e5a39ab239aad8c1e03d27a1378e4bcbf8937eac4300a");
ed25519::Verifier verifier((uint8_t*)pub.data());
bool ret = verifier.VerifyMessage(
(uint8_t*)message.data(), message.size(),
(uint8_t*)signature.data(), signature.size()
);
cout << "ret: " << ret << endl; // shows 0 (wrong)
It shows 0, what's wrong with the code?
libsignal has a customized implementation on curve25519_verification:
curve25519 public key is converted to ed25519 public key (see here)
the verification is done using ed25519 signature verification algorithm (see here)
If you try to verify the signature using the converted ed25519 public key with CryptoPP, the verification would fail. That's because the sign and edd25519_verify operations are also slightly adjusted in libsignal.

How to unbox multivalue string in c++ winrt

I can look for services on the network using
std::vector<hstring> propertyKeys = std::vector<hstring>();
propertyKeys.push_back(L"System.Devices.Dnssd.HostName");
propertyKeys.push_back(L"System.Devices.IpAddress");
hstring aqsQueryString = L"System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.ServiceName:=\"_http._tcp\" AND System.Devices.Dnssd.Domain:=\"local\"";
auto watcher = DeviceInformation::CreateWatcher(aqsQueryString, propertyKeys, DeviceInformationKind::AssociationEndpointService);
I then set the Updated callback to get information about services.
watcher.Updated([](DeviceWatcher sender, DeviceInformationUpdate info) {
for(auto const& p : info.Properties()){
hstring s = unbox_value_or<hstring>(p.Value(), L""); // This unboxes the Hostname
auto ips = unbox_value_or<???>(p.Value(), ???); // How do I unbox this?
}
}
According to Microsoft Documentation the System.Devices.IpAddress is of type Multivalue String. I've tried with std::vector<hstring> but that doesn't work as the type must be a winrt type.
What type do I put to unbox a multivalue string?
I managed to solve it using Sean Kellys answer from here: Equivalent of Platform::IBoxArray in C++/WinRT
Specifically my implementation for printing the first IP looks like this:
auto prop = info.Properties();
auto ips = prop.Lookup(L"System.Devices.IpAddress").as<Windows::Foundation::IReferenceArray<hstring>>();
winrt::com_array<hstring> arr;
ips.GetStringArray(arr);
std::wcout << arr[0].c_str() << std::endl;

How to test endorsement policy for the business network in multiple organizations

I have following this tutorial to setup multiple organizations. According to step 13 before committing transaction requires both organizations should sign off. How can I test that both organizations are endorsing transaction?
Give the proposal responses you are receiving from endorsing peer you can iterate to check validity of the signatures. Here for example code from Java SDK which handles this:
/*
* Verifies that a Proposal response is properly signed. The payload is the
* concatenation of the response payload byte string and the endorsement The
* certificate (public key) is gotten from the Endorsement.Endorser.IdBytes
* field
*
* #param crypto the CryptoPrimitives instance to be used for signing and
* verification
*
* #return true/false depending on result of signature verification
*/
public boolean verify(CryptoSuite crypto) {
if (isVerified()) { // check if this proposalResponse was already verified by client code
return isVerified();
}
if (isInvalid()) {
this.isVerified = false;
}
FabricProposalResponse.Endorsement endorsement = this.proposalResponse.getEndorsement();
ByteString sig = endorsement.getSignature();
try {
Identities.SerializedIdentity endorser = Identities.SerializedIdentity
.parseFrom(endorsement.getEndorser());
ByteString plainText = proposalResponse.getPayload().concat(endorsement.getEndorser());
if (config.extraLogLevel(10)) {
if (null != diagnosticFileDumper) {
StringBuilder sb = new StringBuilder(10000);
sb.append("payload TransactionBuilderbytes in hex: " + DatatypeConverter.printHexBinary(proposalResponse.getPayload().toByteArray()));
sb.append("\n");
sb.append("endorser bytes in hex: "
+ DatatypeConverter.printHexBinary(endorsement.getEndorser().toByteArray()));
sb.append("\n");
sb.append("plainText bytes in hex: " + DatatypeConverter.printHexBinary(plainText.toByteArray()));
logger.trace("payload TransactionBuilderbytes: " +
diagnosticFileDumper.createDiagnosticFile(sb.toString()));
}
}
this.isVerified = crypto.verify(endorser.getIdBytes().toByteArray(), config.getSignatureAlgorithm(),
sig.toByteArray(), plainText.toByteArray()
);
} catch (InvalidProtocolBufferException | CryptoException e) {
logger.error("verify: Cannot retrieve peer identity from ProposalResponse. Error is: " + e.getMessage(), e);
this.isVerified = false;
}
return this.isVerified;
} // verify
Of course you can achive same results with other SDK in pretty similar way.

AWS query through Qt (mac - OSX) is not getting any result

I'm currently trying to create a C++ program to track prices for a bunch of ASINs.
I'm using C++ with Qt (Version 5.5), compiling on mac OSX through Xcode (5.1.1).
When compiling, it's running but no output is given. I have the following warning message instead (I encrypted AccessKey & AssociateTag for privacy reasons as "/////////////")
*QUrl("http://ecs.amazonaws.com/onca/xml?AWSAccessKeyId=///////////////&AssociateTag=/////////////&ItemId=B00181T20O&Operation=ItemLookup&ResponseGroup=OfferSummary&Service=AWSECommerceService&Signature=1K69SLmTkZ9hZwwt5ualR4uDRwY%3D&SignatureMethod=HmacSHA1&Timestamp=2017-01-04T10%3A21%3A46Z")
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
qt.network.ssl: Error receiving trust for a CA certificate
"<?xml version=\"1.0\"?>\n<ItemLookupErrorResponse
xmlns=\"http://ecs.amazonaws.com/doc/2005-10-05/\"><Error>
<Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated
does not match the signature you provided. Check your AWS Secret Access Key and
signing method. Consult the service documentation for details.</Message></Error>
<RequestId>f4626242-a110-43f1-9b56-b8a696b3f299</RequestId>
</ItemLookupErrorResponse>"
RET:
("", "")*
To test it again, I copied URL (first few rows of warning message) in the browser and I get the same error as well:
"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details."
Can anyone give me a hint of what's wrong in the URL?
Thanks in advance!
this is the most relevant part of the code. I suspect I cannot embed .zip file
AWSQueryRequest::AWSQueryRequest(QObject *parent) :
QObject(parent)
{
m_netManager = new QNetworkAccessManager(this);
}
QString AWSQueryRequest::hmacSha1(QByteArray key, QByteArray baseString)
{
int blockSize = 64; // HMAC-SHA-1 block size, defined in SHA-1 standard
if (key.length() > blockSize)
{
// if key is longer than block size (64), reduce key length with SHA-1 compression
key = QCryptographicHash::hash(key, QCryptographicHash::Sha1);
}
QByteArray innerPadding(blockSize, char(0x36)); // initialize inner padding with char "6"
QByteArray outerPadding(blockSize, char(0x5c)); // initialize outer padding with char "quot;
// ascii characters 0x36 ("6") and 0x5c ("quot;) are selected because they have large
// Hamming distance (http://en.wikipedia.org/wiki/Hamming_distance)
for (int i = 0; i < key.length(); i++)
{
innerPadding[i] = innerPadding[i] ^ key.at(i); // XOR operation between every byte in key and innerpadding, of key length
outerPadding[i] = outerPadding[i] ^ key.at(i); // XOR operation between every byte in key and outerpadding, of key length
}
// result = hash ( outerPadding CONCAT hash ( innerPadding CONCAT baseString ) ).toBase64
QByteArray total = outerPadding;
QByteArray part = innerPadding;
part.append(baseString);
total.append(QCryptographicHash::hash(part, QCryptographicHash::Sha1));
QByteArray hashed = QCryptographicHash::hash(total, QCryptographicHash::Sha1);
return hashed.toBase64();
}
QByteArray AWSQueryRequest::getTimeStamp()
{
QDateTime dateTime = QDateTime::currentDateTimeUtc();
return dateTime.toString(Qt::ISODate).toUtf8();
}
QByteArray AWSQueryRequest::createSignature(const QMap<QString,QString> & queryItems)
{
QUrl url(END_POINT);
QString stringToSign = "GET\n";
stringToSign.append(url.host() + "\n");
stringToSign.append(url.path() + "\n");
QList<QString> keys = queryItems.keys();
for( int i=0; i < keys.count() ; ++i )
{
stringToSign.append(keys[i]+"="+queryItems[keys[i]]);
if( i != keys.count() -1 )
stringToSign.append("&");
}
QString signature = hmacSha1(AWS_PASS, stringToSign.toUtf8());
return QUrl::toPercentEncoding(signature);
}
#if 0
QByteArray AWSQueryRequest::createSignature(const QList< QPair<QString,QString> > & queryItems)
{
QUrl url(END_POINT);
QString stringToSign = "GET\n";
stringToSign.append(url.host() + "\n");
stringToSign.append(url.path() + "\n");
for (int i=0; i<queryItems.count(); ++i)
{
QPair<QString,QString> pairValue = queryItems[i];
stringToSign.append(pairValue.first+"="+pairValue.second);
if( i != queryItems.count() -1)
stringToSign.append("&");
}
QString signature = hmacSha1(AWS_PASS, stringToSign.toUtf8());
return QUrl::toPercentEncoding(signature);
}
#endif
QUrl AWSQueryRequest::createUrl( const QMap< QString,QString >& queryItems )
{
QUrl url(END_POINT);
QUrlQuery query;
QMapIterator<QString, QString> it(queryItems);
while (it.hasNext())
{
it.next();
query.addQueryItem(it.key().toUtf8(), it.value().toUtf8());
}
url.setQuery(query);
return url;
}

Get CryptoAPI public key via PKCS#11

In my C++ program I created a public/private key pair using CryptoAPI.
CryptGenKey(eTokenProv,ENCRYPT_ALGORITHM,CRYPT_EXPORTABLE,&k1)
Keys are stored in a eToken.
Is it possible to get the public key using PKCS#11? The private key previously created is found after a search using the following search-template:
CK_ATTRIBUTE private_search[] = {
{CKA_PRIVATE, CK_TRUE, sizeof(CK_BBOOL)}
};
If I set CKA_PRIVATE to CK_FALSE, I can't get the public key. I also tried with other attributes.
Is there a way to do it?
EDIT
As owlstead suggests, I tried to create a public key starting from the modulus and public exponent of a key created in a previous session (in CAPI or, just for this test, in PKCS11). I got the modulus and public exponent from a private key in these buffers:
CK_BYTE modulus[128]; //if 1024bit
CK_BYTE publicExponent[4]; //4 Byte, according to public key blob
But when I try to create a new public with key with the following instructions:
CK_ATTRIBUTE publicKeyTemplate[] = {
{CKA_TOKEN, &yes, sizeof(true)},
{CKA_WRAP, &yes, sizeof(true)},
{CKA_ENCRYPT, &yes, sizeof(true)},
{CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)},
{CKA_MODULUS, &modulus, sizeof(modulus)},
{CKA_PUBLIC_EXPONENT, &publicExponent, sizeof(publicExponent)}
CK_MECHANISM mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
rv = (*functions->C_GenerateKeyPair) (session, &mechanism, publicKeyTemplate, 6, privateKeyTemplate, 6, &hPublicKey, &hPrivateKey);
I get the error "Invalid template". The probles is the modulus, because, without it, I can create a key pair. I use the function C_GenerateKeyPair, but I'm only interested in the public key. I omitted the private template.
What is the wrong here?
CKA_PRIVATE does not indicate a private key at all.
When the CKA_PRIVATE attribute is TRUE, a user may not access the object until the user
has been authenticated to the token
Instead you should look for an attribute such as CKA_CLASS with a value CKO_PUBLIC_KEY or CKO_PRIVATE_KEY, possibly using other attributes to filter your results further.
If you cannot find any CKO_PUBLIC_KEY then I presume it was either not generated in the token (key was imported, check if CKA_LOCAL is set). Alternatively, it may have only been created as a session object. Finally it may have been removed.
Note that RSA private keys commonly do contain the public exponent, so you can still construct a public key from just the private key object (using the modulus and public exponent, of course).
Remove the reference symbol in CK_ATTRIBUTE when setting a pointer to a CK_BYTE array - in your case modulus.
CK_ATTRIBUTE publicKeyTemplate[] = {
{CKA_TOKEN, &yes, sizeof(true)},
{CKA_WRAP, &yes, sizeof(true)},
{CKA_ENCRYPT, &yes, sizeof(true)},
{CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)},
{CKA_MODULUS, modulus, sizeof(modulus)},
{CKA_PUBLIC_EXPONENT, &publicExponent, sizeof(publicExponent)}
I haven't tested your code, but I am able to successfully obtain modulus of an CK_OBJECT_HANDLE (private key / public key) by setting following template and making a call to C_GetAttributeValue:
CK_BYTE modulus[128];
CK_ATTRIBUTE Modulus = { CKA_MODULUS, modulus, sizeof(modulus) };
if ((rv = (*p11FunctionList->C_GetAttributeValue)(hSession, hPrivKey /*hPubKey*/, &Modulus, 1)) == CKR_OK)
{
// do something with obtained modulus
}
The generated private-public key pair was generated as follow:
CK_OBJECT_HANDLE hPrivKey, hPubKey;
CK_BBOOL bTrue = TRUE;
CK_ULONG mod_bits = 1024;
CK_MECHANISM GenMechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
CK_ATTRIBUTE GenPubTemplate[] = {
{ CKA_MODULUS_BITS, &mod_bits, sizeof(CK_ULONG) },
{ CKA_PUBLIC_EXPONENT, "\x01\x00\x01", 3 },
{ CKA_TOKEN, &bTrue, sizeof(CK_BBOOL) },
{ CKA_ID, (CK_CHAR_PTR)szKeyID, strlen(szKeyID) } }; // szKeyID is a const char *
CK_ATTRIBUTE GenPrivTemplate[] = {
{ CKA_TOKEN, &bTrue, sizeof(CK_BBOOL) },
{ CKA_PRIVATE, &bTrue, sizeof(CK_BBOOL) },
{ CKA_SENSITIVE, &bTrue, sizeof(CK_BBOOL) },
{ CKA_ID, (CK_CHAR_PTR)szKeyID, strlen(szKeyID) } }; // szKeyID is a const char *
// hSession is a CK_SESSION_HANDLE of an opened & logged in session
if ((rv = (*p11FunctionList->C_GenerateKeyPair)(hSession, &GenMechanism, GenPubTemplate, 4, GenPrivTemplate, 4, &hPubKey, &hPrivKey)) == CKR_OK)
{
// Now get the modulus of a the private / public key as described above
}
Though this has already been answered for others who want to do this we have created a PKCS#11 based wrapper for CryptoAPI, you can find it here:
https://github.com/PeculiarVentures/pvpkcs11
With this you can access keys stored in CryptoAPI as well as certificates using the native PKCS#11 interfaces.