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
Related
With citrix netscaler update, the OTP is now encrepted in the active Directory attribute.
The OTP explorer tool created by Andreas Nick was working perfectly up to now.
https://www.andreasnick.com/102-otpedit.html
The citrix Documentation says that the OTP secret is now encrypted by the certificate. After the encryption, the HASH string that is stored in the Active Directory attribute looks like this.
OTP Secret
3DHAZHNBYLK72SFKVUOLU6E4ZE
Hash (in Active Directory)
jjtTl0YY3MGIF77HPcqYs2w2bAc=.sbntdorhH2Ju15c5.kbJ8_AP8Ytu7BiNuICEfkiSgOVJMudtNXgn2eStfoOGyV42v6VbzLA==
I tried to encrypt the OTP secret with the certificate used but they are a lot more caracters (346 in total - citrix encryption has 102).
On the citrix website it says that it is using base64 to encrypt the data.
https://docs.citrix.com/en-us/citrix-adc/current-release/aaa-tm/authentication-methods/native-otp-authentication/otp-encryption-tool.html
I tried to use this code but the HASH is not good.
$enc = [system.Text.Encoding]::UTF8
$string = "3DHAZHNBYLK72SFKVUOLU6E4ZE"
$data=$enc.GetBytes($string)
$sha1 = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider
$ResultHash = $sha1.ComputeHash($data)
$str_out = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($ResultHash))
write-host $str_out
My guess is that it is using the certificate thumprint as a "key" but I was not able to find a function that encrypts a string in base64 using a key / passphrase.
I have tried other functions created to encrypt strings from a certificate, but was unable to find one that matches the one done by Citrix.
I am not good in all the encryption. I only know the very basics so the answer might be obvious and that I can simply not see it due to my lack of skills in that area.
Thank you in advance for your help.
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?
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.
When using Set-AuthenticodeSignature, there is an option called IncludeChain. While there is documentation about what each of the options are, I haven't been able to uncover much guidance surrounding the advantages/disadvantages of each setting (when you would pick one setting over another).
Everywhere I see IncludeChain in examples, it is always set to All. I think All is likely the best answer, but I'd like to understand the benefits and disadvantages of each of the settings.
Signer
NotRoot (default)
All
Other than All making the file quite a bit bigger, what are the specific advantages and disadvantages of each of the settings?
References
https://technet.microsoft.com/en-us/library/hh847874.aspx
http://go.microsoft.com/fwlink/?LinkID=113391
How Can I Prevent Needing to Re-sign My Code Every 1 or 2 Years?
Example
$certPfx = "super secret location"
$certPassword = "super secret password"
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certPfx, $certPassword)
Set-AuthenticodeSignature -Filepath "ps1 file location" `
-Cert $cert `
-TimeStampServer "url to timestamp server" `
-IncludeChain All `
-HashAlgorithm SHA256
Default NotRoot is the best option.
Signer
pros: when you put only signer certificate, signature size is relatively small.
cons: if recipient do not have all information to construct the chain, valid signature may become invalid. In addition, certificate retrieval from the internet causes noticeable delays during signature validation.
NotRoot
pros: reduces signature validation time by speeding up chain building with attached intermediate CA certificates. In the case when no extra information about chain certificates available (say, through local store or AIA extension), these certificates fill the gap and greatly help in chain building.
cons: signature size is increased by about 2kb per each intermediate CA certificate.
All
pros: reduces signature validation time by speeding up chain building with attached intermediate CA certificates.
cons: signature size is increased by about 2kb per each CA certificate. This option includes root CA, which is redundant information. If client already have root certificate trusted (as the result it is already installed), included root CA certificate do not provide any helpful information. If client do not have root certificate, its inclusion in the signature doesn't make sense either.
This is one of my first approaches to "crypto in practice". I have found myself a new aim when I stumbled upon my password (AES encrypted) on my FTP server. Since I am eager to get to know new stuff, I decided I'll give it a go and try to 'recover' my password from AES cipher. If I can make it to decipher it 'on the paper' I think I will have a good enough understanding on how it works and how to call it.
As MSDN points out:
The AesProvider provider is an AES provider that uses a session key encrypted using an RSA key container that has permissions for the IIS_IUSRS group, therefore allowing IIS worker processes to encrypt and decrypt configuration encrypted with this provider.
So, the available data:
Session key (RSA encrypted) from <configProtectedData>
AES cipher from the same file (enc:AesProvider:89v45avZx.....)
Machine RSA key (obtained using aspnet_regiis -px "SampleKeys"
keys.xml -pri) (since useMachineContainer flag is true).
If I understand correctly:
In order to decrypt the password:
I need to decrypt the RSA-Encrypted session key with Machine RSA key.
Once I have the decrypted session key I use it as AES key to decrypt the password. Am I mistaken in this thinking?
If the above is correct, I will now describe my attempts:
Using Powershell (my preferable environment):
[xml]$IISXML = [xml](cat .\IISConfigKey.xml)
[System.Xml.XmlElement]$IISElement = $IISXML.RSAKeyValue
$RSA = New-Object System.Security.Cryptography.Xml.RSAKeyValue
$RSA.LoadXml($IISElement)
## Now I have RSA-key loaded as an object from exported XML
$AESSessionKey = "LIAAAZ..1aVods=" // Total length 188
## I am importing the session key from the file
$AESProviderSessionKeyBytes = (Convert-FromBase64 $AESProviderSessionKey).ToCharArray() | % { [byte]$_ }
## 'Convert-FromBase64' is my custom function, which basically converts from Base64 to String
And this seems to be the first culprit I can't get around. Casting $RSA.Key.Decrypt($AESProviderSessionKeyBytes, $true) returns an error that the data exceeded 128 bytes. Which happened in fact, as the SessionKeyBytes is of 140-length.
As the method I am calling happily throws exceptions at me, I have no idea what to try next. The sessionKey seems too long to be RSA-encrypted? Or maybe I should divide it? Or maybe I am just mistaken in principle that it is RSA encrypted.. I tried couple of versions, but none of them progressed me any closer.
Hope you can point me in the right direction!