Does certutil's -csp "Microsoft Platform Crypto Provider" option store the private key in the TPM? - private-key

Does certutil -csp "Microsoft Platform Crypto Provider" -importpfx options really store the private key in the TPM? I am wondering why the output of certutil -key -csp "Microsoft Platform Crypto Provider" shows me a location on the harddisk...
Microsoft Platform Crypto Provider:
Test-637559044681743771-7df36675-f51c-4067-9f6d-31ca33d290b7
C:\ProgramData\Microsoft\Crypto\PCPKSP\33b114867a192aae5b73a3a968437c129ab577a4\ec03c4aa087abc780c3ff6448624456b0d1bf68c.PCPKEY
RSA

The private key is wrapped by a key in the TPM (usually the Storage Root Key) and saved to disk. The TPM has to unlock the private key, so it is still secured by the TPM.
It is possible to store a few keys in the TPM, but that's not typical.

Related

Encryption and file format in Kleopatra. Can't encrypt using Public Key

I created PGP key pair and I exported private and public key files. I know that files are fine because I was able to encrypt/decrypt files in GpgFrontend app using these keys. I was also able to do the same using Bouncy Castle library in C#.
Two questions:
1: In Kleopatra, I can't encrypt file with Public Key only. For some reason it doesn't work. Option is not available. To be able to encrypt/decrypt I have to load Private key. What is it that I am missing?
2: I am confused with encrypted data. When I open encrypted PGP file, data looks something like this:
…F†u—PEÛ Ù×´‡Ó"gÆx=ÑoãÝSŒ6M)!ÑÙ×g|;ä #+Pa,²TDV„ëùqá²*”—}×±dCÐÊsf^:Š†7¶LØnš{‹‰ždºV°G­(¸7Rd ôUµD#9ÖÕ÷ü Ý dëE¶-ýû¾/khØÇ~Zˆ0:±ðU5É¥žÇé¯7M Ôà}Ò:ÕÈàÒ€snœ­‘èÁq§ÀJ®zU’èDc%ߘ–yí|걫M„ð™=Üæ0ß| 5|¾ªô Åíú_lªkó‰Ùª>/–þ€ÈðkvÖwãz9Y±ŠÜW½ìFÍþ{ãF­ÔS fýâÚÐpá
8Z_.eÄŽÂU)õœ-•êSQÁ\¼—? ¥ã¢O¯J•ÔÖ D;<kÔPÚ.8ÀKƒNÒ€3túø°ÒºA¼ ‡KèÁ›X
but, when I use Notepad option in Kleopatra (or in GpgFrontend), and when I encrypt some text, encrypted data looks like this:
-----BEGIN PGP MESSAGE-----
hF4D1F0XuQWmdMYSAQdAJaVSF+2pME685EMW2M/xDKPKE6BxJiSYSgP06GGKUVgw
P+7Y91/iMOHz2dB4K2clkjgLbWXvy+DRlkBKXGzs7lSK6c3+HFv1L+EIj+mm+dni
1MAGAQkCEP6UbLZfq+aFWK3Fs4H7j05XYdovJvZv9GKEBQCbGT4PjB1ZrxkC+VfO
ybB5R6cWJMdo1mdUg05KAAfSinOM/19gXBrh2pwO/snX/bK7M1iA+qi0rYcGl7Lu
ijHm6PA1c8LBMKFz7Xc6lcA5CtsLTseHHHGEtQCt6Hd/z0EvQUA0FdiYKcieX/lA
W8y0V+Xjao86VmRNYVryx6pRmbq5+vN7H/9hnDNUxgzxVb/yQ90FePzDK73V/bsT
Im2MNTma9ruB
=j0ZY
-----END PGP MESSAGE-----
Why does encrypted data look different?
Thank you

How should I sign a CSR using a signature created in HSM, in C# .NET Core?

I'm exhausted after looking for an answer for 3 days. I don't know if my suggested flow is wrong or my Google skills have really deteriorated.
My API needs to create a valid certificate from a CSR it received, by signing it with a private key that exists ONLY inside an HSM-like service (Azure KeyVault), which unfortunately doesn't offer Certificate Authority functions BUT does offer signing data with a key that exists there. My CA certificate's private key is stored in the HSM. I'm using ECDSA.
My suggested flow:
Client generates Key Pair + CSR and sends CSR to API
API creates a certificate from the CSR
API asks HSM to sign the CSR data and receives back a signature
API appends the signature to the certificate and returns a signed (and including CA in chain) certificate to the Client
I'm using C# .NET Core and would like to keep it cross-platform (as it runs in Linux containers), so I have to keep it as native as possible or using Bouncy Castle (which I'm still not sure if runs in Linux .NET Core).
I really appreciate your help!
I had faced a similar issue and found a solution. You'll have to use the PKCS11Interop.X509Store library.
The solution uses dotnet core native System.Security.Cryptography.X509Certificates.CertificateRequest::Create method
for generating a certificate.
As per the docs:
Pkcs11Interop is managed library written in C# that brings the
full power of PKCS#11 API to the .NET environment
Pkcs11Interop.X509Store is managed library built on top of
Pkcs11Interop. It's main goal is to provide easy to use PKCS#11 based
read-only X.509 certificate store that can be easily integrated with
standard .NET ecosystem.
Till v0.3.0, implementation for issuing a certificate (i.e signing a CSR) is not available.
With minor modifications in the PKCS11Interop library, I was able to sign the CSR.
Mentioned in Issue #30, the code is now added in the PKCS11Interop.X509Store library version 0.4.0.
The below code is taken from test cases for BasicEcdsaCertificateRequestTest. Test cases for RSA CertificateRequest are also there.
// Load PKCS#11 based store
using (var pkcs11Store = new Pkcs11X509Store(SoftHsm2Manager.LibraryPath, SoftHsm2Manager.PinProvider))
{
// Find signing certificate (CA certificate)
Pkcs11X509Certificate pkcs11CertOfCertificateAuthority = Helpers.GetCertificate(pkcs11Store, SoftHsm2Manager.Token1Label, SoftHsm2Manager.Token1TestUserEcdsaLabel);
// Generate new key pair for end entity
ECDsa ecKeyPairOfEndEntity = ECDsa.Create(ECCurve.NamedCurves.nistP256);
// Define certificate request
CertificateRequest certificateRequest = new CertificateRequest(
new X500DistinguishedName("C=SK,L=Bratislava,CN=BasicEcdsaCertificateRequestTest"),
ecKeyPairOfEndEntity,
HashAlgorithmName.SHA256);
// Define certificate extensions
certificateRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, true));
certificateRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(certificateRequest.PublicKey, false));
certificateRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, false));
// Issue X.509 certificate for end entity
X509Certificate2 certificateOfEndEntity = certificateRequest.Create(
pkcs11CertOfCertificateAuthority.Info.ParsedCertificate.SubjectName,
X509SignatureGenerator.CreateForECDsa(pkcs11CertOfCertificateAuthority.GetECDsaPrivateKey()),
DateTimeOffset.UtcNow,
DateTimeOffset.UtcNow.AddDays(365),
new BigInteger(1).ToByteArray());
// Verify signature on X.509 certificate for end entity
Assert.IsTrue(CaCertSignedEndEntityCert(pkcs11CertOfCertificateAuthority.Info.ParsedCertificate.RawData, certificateOfEndEntity.RawData));
// Asociate end entity certificate with its private key
certificateOfEndEntity = certificateOfEndEntity.CopyWithPrivateKey(ecKeyPairOfEndEntity);
// Export end entity certificate to PKCS#12 file
string basePath = Helpers.GetBasePath();
string pkcs12FilePath = Path.Combine(basePath, "BasicEcdsaCertificateRequestTest.p12");
File.WriteAllBytes(pkcs12FilePath, certificateOfEndEntity.Export(X509ContentType.Pkcs12, "password"));
}
Hope this helps.

How to generate a certificate with DH parameters

I need to support Diffie Hellman encryption, now in order to test this i need to create a certificate with DH key parameters eg. key-length - 2048 etc.
Now as i understand DH doesn't work with self-signed certificates, so basically i need to create a certificate issued by some trusted third party containing DH key parameters.
I searched a lot but can't seem to find proper direction, no where can i find a way to create a cert with DH parameters.
Can someone point me in right direction?? Thanks in advance!!
I need to support Diffie Hellman encryption
DH is key exchange (or key agreement) protocol, not encryption. DH is used to securely generate a common key between two parties, other algorithms are used for encryption itself.
I need to create a certificate with DH key parameters eg. key-length - 2048 etc
There is nothing like DH parameters in a certificate.
DH is only one of ways how a public key can be used. You may generate a DH public key with specified length (e.g. 2048 bit) and execute the DH exchange, but it has nothing to do with certificate parameters. (didn't you mean to generate a keypair, not a certificate?).
Indeed the DH key exchange needs other parameters (p, g), but the parameters are part of the protocol, not the certificate. In TLS even the DH parameters can be random and authenticated by the certificate's public key - it is called Ephemeral Diffie-Hellman key exchange.
You could generate DH parameters (p, g) separately:
openssl dhparam -out dhparams.pem 4096
Can someone point me in right direction??
Now I assume you want to establish an encrypted channel (TLS) using DH. The easiest way would be to specify allowed parameters for SSL for the library. This is an example httpd configuration, where you can enforce DH key exchange. Every reasonable SSL framework or server has option to set the parameters.
If you want to do the DH key exchange yourself (not as part of TLS), I'd advice to use an out-of-box mature library for your programming language.
Yes, it seems true that OpenSSL will not create a certificate for DH keys. You'll get an error like: operation not supported for this keytype. The reason someone would want to do this is that they want to store the DH public key in a keystore; which seems like a reasonable place to store them. In my case, I want my client application to be deployed with the server's public DH key. The problem is that keystores don't let you store public keys in them. They do however, let you store certificates in them. Hence the need for creating a certificate that contains a DH public key. Since you can't do this using OpenSSL, you'll have to do it in code. Here's the code that I use to create a certificate. If you pass in a DH public key, you'll be able to add this certificate to a keystore:
public X509Certificate createCert (PublicKey publicKey, PrivateKey caKey, X509Certificate caCert , String subject) throws Exception {
Date now = new Date();
Date exp = new Date(now.getTime()+2555*86400*1000); // 2555 days validity
BigInteger.valueOf(now.getTime());
ContentSigner signer = new JcaContentSignerBuilder("SHA256with"+caKey.getAlgorithm()).build(caKey);
SubjectPublicKeyInfo subPubKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
byte[] enc = new X509v3CertificateBuilder(
/*issuer*/ new X500Name(caCert.getIssuerX500Principal().getName()),
/*serial*/BigInteger.valueOf(now.getTime()),
/*validity*/now, exp,
/*subject*/new X500Name (subject),
/*spki*/subPubKeyInfo).build(signer).getEncoded();
X509Certificate cert = (X509Certificate)CertificateFactory.getInstance ("X.509") .generateCertificate(new ByteArrayInputStream(enc));
return cert;
}
The code uses several BouncyCastle classes. Besides passing in the DH public key, you have to pass in the CA private key and the CA certificate and a String that contains the subject for the certificate that you generate. Hope that helps for those wanting to store a DH public key in a keystore.

Convert private key to PKCS#8 format in java

I'm trying to get certificates and private keys from windows certificate store using MSCAPI provider, then i need to store them in a Java Keystore object, but i'm facing a problem of private keys format, the error says:
java.security.KeyStoreException: Cannot get key bytes, not PKCS#8 encoded
Here's my code:
SunMSCAPI providerMSCAPI = new SunMSCAPI();
Security.addProvider(providerMSCAPI);
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);
PrivateKey privateKey = null;
X509Certificate cert = null;
cert = (X509Certificate) ks.getCertificate("ALIAS");
if (ks.isKeyEntry("ALIAS")) {
privateKey = (PrivateKey) ks.getKey("ALIAS", null);
}
KeyStore newKs = null;
...
...
newKs .setKeyEntry("pvKey", privateKey , "pwd".toCharArray(), certifChain);
Also, the privateKey.getEncoded() returns null.
I have exactly the same issue when programatically importing a pfx file into the windows certificate store and then attempting to read this certificate and key again later. I believe the answer lies in http://www.oracle.com/technetwork/articles/javase/security-137537.html and I quote: "...the resulting PKCS#12 keystore may not be imported into applications that use only a single password for the keystore and all its key entries". Earlier in the document it also states: "Note that keys produced by the SunMSCAPI provider are wrapper objects for the native handles. Thus, they may not be accepted by other providers and may behave somewhat differently than keys produced by pure-Java providers, such as SunJCE. In particular, the RSA private keys generated by the SunMSCAPI provider cannot be serialised". Upon trying to read the private key results in null algorithm and null encoded data as you note above, though reading the certificate works fine. Alternatively you could save the PrivateKey in a separate RSA encrypted file instead of the windows certificate store or just work of the original pfx file instead of importing the pfx into the windows certificate store.
I use command such like:
Runtime.getRuntime().exec("openssl pkcs8 -topk8 -nocrypt -in "+ privateKeyPath + " -out " + pkcs8PrivateKeyPath)

Need to send a string to another server with PGP encryption

A client is asking my to post a xml string to a third party. The catch is that the xml has to be encrypted with PGP they have provided me with a public key that looks like this:
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.14 (GNU/Linux)
There is very little info online about doing this with ColdFusion that I can find. There is a project on riaForge http://pgp.riaforge.org/index.cfm that looks like it may do the job but it requires installing on the server.
My question, is installing PGP on the server the only way to do this. I haven't even hear about PGP in a decade and have never had to encrypt anything with it so any insight would be very appreciated.

Resources