How do I verify a root DNS trust anchor? - perl

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.

Related

How to Parse P12 File

I'm writing a parse tool to extract each field of P12 file in C language, OpenSSL is too huge for my project.
After reading PKCS# series documents and ASN.1 documents, I understand the basic parse step.
I use OpenSSL to generate a self-signed P12 file,there're some questions during parsing:
Why Certificate is not stored in a Safebag, in my case it's stored in EncryptedData field?
What does the localKeyId attribute mean? it has an OctetString, what is the OctectString used for?
Why the contentType of encryptedContentInfo is id-data? I think it should be id-encryptedData. In my case, Certificate is stored in encryptedContentInfo field.
Thanks,
CZ
The PKCS12 standard also available as rfc7292 formally allows a very wide range and combination of options, but in practice only a few of these options are used. There are basically 3 levels:
the file has type/structure PFX consisting mostly of a PKCS7/CMS ContentInfo which theoretically can be 'data' or 'signed-data' but in practice is always the former (with the nominally optional MacData appended) and contains
'AuthenticatedSafe' which is a sequence of one or more (almost always more) ContentInfo(s) each of which (separately) may be encrypted or not and contains (after decryption if applicable)
a sequence of one of more 'bag'(s) each of which contains actual data of a certain type such as an encrypted privatekey or a certificate along with optional attributes.
In practice there is usually:
one CI (at level 2) with PKCS7/CMS type 'encrypted-data' using a very weak algorithm (RC2-40) containing one or more CertBag(s) each containing a cert plus any attributes for it, and
one or more CI(s) (each) with type 'data' containing a PKCS8ShroudedKeyBag containing an encrypted privatekey (using PKCS8 as stated) usually using a strong algorithm commonly 3DES, plus attributes.
My answer here shows the first levels of parsing to find the encryption details; further parsing requires decryption as shown (for a specific case) in my answer here.
As mentioned all bags can have attributes; in practice depending on the implementation some bags may have the 'friendlyName' attribute with a value intended for people to use, and if a matching privatekey and cert are present they both have a 'localKeyId' attribute with the same value to tie them together, as explained in my answer to a different but related Q. 'localKeyId' is not intended for people to use and you should not normally present it to people.

How can I add a private key to a certificate in the windows trust store in c++?

I have a file with a certificate in it, and I have a file with a private key file in it.
if I run this command
certutil –MergePFX certfile.cer certfile.pfx
I get a pfx file that if I run with explorer, it runs the windows certificate import wizard. If I run through the wizard, I end up with the cert with the key in the windows trust store. Exactly what I need.
I'm trying to do this programatically.
The problem seems to be in the CertAddCertificateContextToStore function.
In the remarks it says:
The certificate context is not duplicated using CertDuplicateCertificateContext. Instead, the function creates a new copy of the context and adds it to the store. In addition to the encoded certificate, CertDuplicateCertificateContext also copies the context's properties, with the exception of the CERT_KEY_PROV_HANDLE_PROP_ID and CERT_KEY_CONTEXT_PROP_ID properties.
So certduplicatecertificatecontext very specifically will not copy the private key, and it seems that CertAddCertificateContextToStore doesn't either.
I have a HCRYPTPROV struct with my private key and I use CERT_KEY_CONTEXT_PROP_ID and CERT_KEY_PROV_HANDLE_PROP_ID (I tried them both) to CertSetCertificateContextProperty my certificate context, and then I store it in the windows trust store with CertAddCertificateContextToStore. And no matter what I try, the certificate goes in without the private key.
I'm verifying this with the certmgr tool that shows if a private key is attached, and I can also see it not work when I use that client certificate in a curl request I'm making.
Another thing I tried was this:
The last parameter to CertAddCertificateContextToStore is the handle to the copy of the context that is made. I figure the original context is the one I created where I read the certificate in from disk. This new certificate is the one tied to the actual on-disk store that certmgr reads.
So after I call CertAddCertificateContextToStore, I take the new cert and I add the private key, again via CertSetCertificateContextProperty, and then for good measure, I call CertControlStore to push the in-memory version of the context to disk. Still no effect. Every function call succeeds, but the private key never makes it to the windows trust store.
So in short, my question is what is the windows certificate import tool doing that I am not that will allow me to store a private key along with the certificate in the windows trust store?
I've found a handful of other questions and program examples and message boards dating back to 2002 and none are very explicit, and none of the code examples do exactly what I need, but I know I have all the pieces, they just don't yield the result.
I strongly believe that you set incorrect properties. You should set only CERT_KEY_PROV_INFO_PROP_ID context property in the CertSetCertificateContextProperty call to associate certificate with private key.
If you have a HCRYPTPROV handle, then you have all necessary information to construct CRYPT_KEY_PROV_INFO structure.

How to validate an RSA cert in 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.

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 to issue certificate to an entity with custom DN format?

In our application we generate certificates for internal entities like platform and user. Our internal entities are identified by custom DNs:
Platform DN: p=platformName
User DN: cn=userName,p=platformName
We tried to generate X.509 certificate for platform or user with popular tools like openssl, keytool, implementation of javax.security (BouncyCastle), e.g.:
keytool -genkey -dname "p=platformName" -alias platformName
However, those tools do not accept/recognize keyword "P" or require certain keywords like "CN" in certificate subject DN.
How to issue certificate to an entity with custom DN format?
Note: We do not need to have DNs containing standard keywords (CN, OU, etc.), because all certificates will be for internal use of our products (will not be validated by 3rd party or included in certificate chain).
We do not need to have DNs containing standard keywords (CN, OU, etc.)
How to issue certificate to an entity with custom DN format?
The attributes or fields displayed are a presentation level detail. There is no distinguished DN field per se. The fields used to form the DN are a mashup of other attributes and are arbitrarily chosen. The common ones are C, O, OU, CN, etc.
Attributes or fields like C, O, OU, CN have well known OIDs associated with them. There are other OIDs you can use that are recognized by tools. For example, the ITU's X.520 list hundreds of them. There are other standards that declare them too. For example, the email address attribute is from PKCS 9 and has an OID of 1.2.840.113549.1.9.1.
As Burhan Khalid stated, you can even add your own name/value pairs by making up OIDs (some hand waiving). However, other presentation tools won't know how to display them. That is, they won't know the "friendly name".
Because other tools don't recognize your OID for platform (or "p=..."), that's why you are getting ... those tools do not accept/recognize keyword "P". The tools don't know how to deal with your custom attributes.
I can only speak for openssl, as I am not familiar with other tools.
From the openssl docs
ASN1 OBJECT CONFIGURATION MODULE
This module has the name oid_section. The value of this variable
points to a section containing name value pairs of OIDs: the name is
the OID short and long name, the value is the numerical form of the
OID. Although some of the openssl utility sub commands already have
their own ASN1 OBJECT section functionality not all do. By using the
ASN1 OBJECT configuration module all the openssl utility sub commands
can see the new objects as well as any compliant applications.
So what you have to do is create these oids in /etc/openssl.conf or wherever the file is for your platform, then openssl will not give you the Subject attribute p has no known NID, skipped message, which I suspect is what you are getting now.