How to validate an RSA cert in perl - perl

How do you validate an cert given a root cert that signed it? I've got this far:
$root_x509 = Crypt::OpenSSL::X509->new_from_string($root_key_data, FORMAT_ASN1);
$root_key = Crypt::OpenSSL::RSA->new_public_key($x509->pubkey());
$other_x509 = Crypt::OpenSSL::X509->new_from_string($other_key_data, FORMAT_ASN1);
$other_key = Crypt::OpenSSL::RSA->new_public_key($x509->pubkey());
Ok, then what? I'm not seeing an obvious $root_key->verify_certificate($other_x509); Is Crypt::OpenSSL::VerifyX509 the only/best answer? That module is being problematic to compile and install, but I'll continue in that vein if it's the way to go. But I feel like I'm missing something.
It looks like python, for example, has an obvious API an equivalent to which I'm not seeing in any of the OpenSSL perl libraries:
trusted_store = X509Store()
trusted_store.add_cert(trusted_root)
try:
X509StoreContext(trusted_store, itunes_cert).verify_certificate()
except X509StoreContextError as e:
print("iTunes certificate invalid")

After extensive research, the closest thing to a complete solution besides Crypt::OpenSSL::VerifyX509 (see above) is Net::SSLeay, which has a whole bunch of low-level bindings to openssl. They recently added these:
1.83 2018-01-06
X509_STORE_CTX_new and X509_verify_cert
but the documentation is sparse, and I wasn't able to get past related segfaults.
Instead I validated the cert chain by hand:
use Convert::ASN1 to re-encode the tbsCertificate data I had decoded
in my PKCS#7 file ("tbs" is "to-be-signed")
get the signature from the PCKS#7 data
get the subjectPublicKeyInfo.subjectPublic Key from the cert that signed this cert
feed that to $signer_key = Crypt::OpenSSL::RSA->new_public_key($signer_key_pem);
and then do $signer_key->verify($cert_as_signed, $signature)
and repeat for each cert in the chain.
Checking validity dates and extension capabilities on each cert is part of all that.

Related

Digital Signature Certificate

I've been all around Google and I feel like I've just gone into a deep rabbit hole.
I'm looking to create a Digital Signature certificate (I assume self-signed?). I ran into the method of using certreq -new .\certname.txt by providing simple parameters.
But the only thing I've come to know that I need in my file is:
[NewRequest]
Subject = "CN=Test Sign, E=email#address.com"
KeyLength = 2048
HashAlgorithm = Sha256
KeyUsage = 0x0080 ; Digital Signature
RequestType = Cert
ValidityPeriodUnits = 1
ValidityPeriod = Years
But I'm unsure of what else should be here in order to make it a proper signature certificate.
I want to be able to use this signature file in whatever project I have going.
I messed around with Adobe Acrobat Pro and you can create a digital sig in that program; but it limits the OID to 1.2.840.113583.1.1.10 which is for Adobe.
In short, I need to place a Digital Sig into slot 9c of my Yubikey. If you generate the certificate from the Yubikey; then the private key is not exportable. So I'm attempting to generate the pfx file this way so that I can import into multiple keys without the need for multiple different certificates.
Any help to finish this up would be greatly appreciated.
Regards

Decrypting AES GCM with Python without Authentication Tag

I will start with a disclaimer that I am out of my depth here. A colleague was showing me a decryption routine he wrote with pycryptodomex. He had an encrypted file, a key, and a nonce (extracted from the file). He was able to decrypt the file contents in a very straight forward way.
c = Crypto.Cipher.AES.new(key, AES.MODE_GCM, nonce)
c.decrypt(encrypted_data)
You can see a similar implementation in the pycryptodome test for GCM:
cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
pt = get_tag_random("plaintext", 16 * 100)
ct = cipher.encrypt(pt)
cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96)
pt2 = cipher.decrypt(ct)
Unfortunately, pycryptdomex is an additional dependency that I would need to carry around and I am looking to avoid this. I have a base installation of Anaconda, which brings with it the pyCrypto and pyCA/cryptography packages. It appears that pycryptodomex is a fork of pyCrytpo, which didn't have a stable GCM implementation to begin with. When I look at the implementation for PyCA/cryptography, it looks straight forward:
cipher = Cipher(algorithms.AES(key), modes.GCM(nonce), backend=default_backend())
d = cipher.decryptor()
But when we want to decrypt content we have to call finalize_with_tag and produce an authentication tag:
d.update(encrypted_data) + d.finalize_with_tag(tag)
Unfortunately, I don't have an authentication tag nor do I know where to find it. I can't set the value to None as there is a minimum length requirement. I'm also not sure why I need to produce an authentication tag in the first place for AES GCM decryption with PyCA/Cryptography but I do not need to produce a tag when decrypting with the pycryptodomex. I'm ultimately looking for clarity on the following:
Is it possible to implement AES/GCM decryption with the Anaconda PyCA/cryptography package if I only have access to the key, nonce, and encrypted data?
Why do I need to provide an authentication tag for decryption with one implementation and not the other?
Is pycryptodomex doing something under the hood to determine the tag?
GCM without authentication tag is equivalent to CTR mode. (except the + 1 difference in starting counter value)
Calling decrypt does not verify the tag (as far as I know). You can test this yourself by altering the ciphertext just one byte. It will decrypt just fine (to a plaintext that is off by one byte). Use decrypt_and_verify (see test_invalid_mac test).
See 2.
Apologies as I can't reply to comments. Is it possible to derive the tag from the decrypted data after decryption? This PR associated with PyCA/cryptography seems to imply the exact scenario considered here.
According to the GCM spec (section 7.2: “Algorithm for the
Authenticated Decryption Function”), the tag itself is not needed
until the ciphertext has been decrypted.
Does calling d.update(encrypted_data) decrypt data successfully and d.finalize() is only needed to verify the integrity of the data?

Signature verification using only a hashed/encoded message

Is there any way to verify the OpenSSL signature using only {signature,hashed message} pair, skipping the original file to be presented for verification?
I need to verify the signature with only {signature,hashed message} pair remotely so using the original file is cumbersome specially when its very large.
Is there any way to verify the OpenSSL signature using only hash value and without needing the original file?
Yes, but there are strings attached.
The scheme which requires the original message to be presented to the verifying function is a Signature Scheme with Appendix (SSA). A scheme like the old PKCS #1.0 signing is an example of it.
The scheme which does not require the original message is a Signature Scheme with Recovery (PSSR). In a PSSR, the encoded message is part of the signature and masked. A scheme like the new PKCS #2.0 PSSR signing is an example of it.
There are no schemes that take just a hash, as far as I know. You have to have the {message,signature} pair. Allowing the message to be disgorged from the signing or verification can be a security violation.
OpenSSL provides both of them, as does most other security libraries, like Botan, Crypto++, NSS, etc.
Also see RSA signature on TLS on Information Security Stack Exchange.
I have been trying to verify the signature with hash value remotely so using the original file is cumbersome specially when its very large.
That's the insecure thing signature schemes want to avoid....

How do I verify a root DNS trust anchor?

I am trying to verify root Key Signing Key (KSK) against the trust anchor (Kjqmt7v.crt) downloaded from here. I am getting root KSK using the Net::DNS module.
I am very confused at present on how to verify that both are the same. I tried to convert the .crt file to a Keyset object, but it is resulting in an error.
This is my code.
#!/usr/bin/perl
use strict;
use warnings;
use Net::DNS::Keyset;
my $keyset = Net::DNS::Keyset->new('Kjqmt7v.crt');
$keyset->print;
This is the error
We expected a match RDATA
0��0���0 *�H�� 0K10 U
this Should not happen
at a.pl line 5
I am very confused and therefore unable to provide any proper code, as I have no idea how to start. Pointing me in the right direction would be very helpful.
I want a way to verify trust anchor against the KSK that I am getting from root DNS servers. If there is any other way to do that please update me.
You seem to have misunderstood what's in the files IANA provides. None of them except the public root key itself is actually DNSSEC data. The Kjqmt7v.crt file, for example, is an X.509 certificate in DER format (so it's no wonder that Net::DNS::Keyset chokes on it). If you look at it (with the openssl x509 command, for example), you can see that included in its DN field is the textual representation of a DS record for the root KSK. So if you verify that certificate, you know that DS is genuine, and you can use that to verify the DNSKEY.
Another alternative available at the same URL, which is probably easier to use for most people, is a DS for the KSK in XML format, with a detached PGP signature. Verify the signature, use the data in the XML file to build a proper DS record in your favorite programming language, and then you can use that to verify the KSK DNSKEY record.

SignedCms.CheckSignature() with renewed cert -> new serial?

i am using
SignedCms.CheckSignature(certColl, true)
(with only one cert in certColl) to verify the signature of a pkcs-7 message. My problem is that i dont want to change the (public part of the) signers certificate on my server after the signer has renewed his certificate :-( The public key, issuer and subject are remaining unchanged after signer has renewed his certificate! So this has to work - at least in my opinion, even if i´m not a crypto-geek :-)
..but, unfortunately the .NET-Framework throws a Cryptographic Exception "Cannot find the original signer" like the stacktrace says exactly at:
SignerInfo.CheckSignature(X509Certificate2Collection extraStore, Boolean verifySignatureOnly)
This must be because the serial number of the signers certificate has changed and the SignerIdentifier property is readonly and set to IssuerAndSerialNumber.
Does anyone know how workaround this?
Or do i have to implement a "handmade" signature verifying with sth like: signedMessage.ComputeSignature(signer, false)?
Thanks in advance and happy programming,
Krile
For all interested on this issue:
Someone told me that this is due to the PKCS #7 specification, which states that the SubjectKeyIdentifier is always set to IssuerAndSerialNumber.