Windows keystores and certificates - windows

I've recently inherited a project with minimal documentation that performs digital signatures of documents and I've received a change request that has left me a little baffled.
The application is Java based, and makes use of Java Keystores (JKS) and uses the private key of the alias specified as a command line operation to digitally sign an input document. This all appears fairly straightforward to me, however the change request has left me confused.
The client has requested the ability to use "Windows" keystores (more specifically, the Windows-MY keystore which relates to personal certificates as far as I can tell). Now, my initial assumption is that what the client is requesting is simply not possible as this key store will only ever contain certificates, which can not be used for signing documents in any capacity. Am I incorrect, or will the Windows-MY keystore only ever contain a public certificate? I don't believe a private key would ever be embedded within one of these certificates.
Unfortunately there are a some communication difficulties so I'd like to make sure my reasoning is correct before proceeding any further.
Here's some more evidence to support my case (communication from the client):
Creating Windows Key Store (Exporting from Java Keystore ) steps are here -
generate RSA key
keytool -genkey -alias mykey -keyalg RSA -keystore my.jks -keysize 2048
Export Certificate from the above keystore:
keytool -export -alias mykey -file mykey.crt -keystore my.jks
Enter keystore password: temp123
Certificate stored in file <mykey.crt>
Install the above certificate in windows keystore.
a. Double click on “mykey.crt” and click on Install certificate
b. Select “Place all certificates in the following store” radio button and click “Browse” button to Added it in windows Certificate store.
c. Check this certificate in WindowsMy store.
Unless I'm wrong, keytool will only ever generate a certificate type rather than an actual public/private key pair?
Any assistance or even affirmation would be greatly appreciated, apologies for the lack of clarity in the question but unfortunately this is all I have to work with at the moment.
Java or Windows specific answers would be helpful but even just confirmation of the basic principles would be appreciated.
Thanks in advance

Maybe you want to take a look at Oracle's documentation [1] on the SunMSCAPI provider, that can be used to access certificates and keys stored in the Windows-MY (Personal) and Windows-ROOT (Trusted Root Certification Authorities) stores.
There is a little code snippet as well, which seems to match your needs quite reasonably:
KeyStore ks = KeyStore.getInstance("Windows-MY");
// Note: When a security manager is installed,
// the following call requires SecurityPermission
// "authProvider.SunMSCAPI".
ks.load(null, null);
byte[] data = ...
String alias = "myRSA";
PrivateKey privKey = (PrivateKey) ks.getKey(alias, null);
Certificate cert = ks.getCertificate(alias);
Provider p = ks.getProvider();
Signature sig = Signature.getInstance("SHA1withRSA", p);
sig.initSign(privKey);
sig.update(data);
byte[] signature = sig.sign();
System.out.println("\tGenerated signature...");
sig.initVerify(cert);
sig.update(data);
if (sig.verify(signature)) {
System.out.println("\tSignature verified!");
}
Summarizing: The Windows-My store holds certificates as well as private keys, both can be read from Java using the SunMSCAPI provider and can be used to sign digital documents.

If simply wanting to use a keytool created (java) keystore's certificate w/ its private key so that you can import it into a windows, then would you just export it to PKCS12 format (PFX). (i.e.; when exporting, use paramter -storetype=pkcs12)

Related

PCF Container TrustManager adds certificates, but TrustManagerFactory loads certificates twice

I run a spring boot app on PCF with an apache-httpclient 4.x. The client creates a ssl context:
final SSLContext sslcontext = SSLContext.getInstance(algorithm);
sslcontext.init(keymanagers, trustmanagers, params.getSecureRandom());
I get the trustmanagers as follows:
final TrustManagerFactory tmfactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmfactory.init((KeyStore) null);
I log the number of certificates it finds and I log the found CN's. However I found it list every certificate twice!
If I provide a keystore with 1 certificate:
tmfactory.init((KeyStore) truststore);
It will log that certificate + all environment certificates. As follows:
private static void logAcceptedIssuers(TrustManager[] trustmanagers) {
log.info("Adding the following trusted certificates to the SSL context: ");
Arrays.stream(trustmanagers)
.filter(X509TrustManagerWrapper.class::isInstance)
.map(X509TrustManagerWrapper.class::cast)
.map(X509TrustManagerWrapper::getAcceptedIssuers)
.forEach(SSLContextFactory::logAcceptedIssuers);
}
private static void logAcceptedIssuers(final X509Certificate[] certificates) {
final int certificatesCount = certificates.length;
final String prefix = "Trusted certificates (total=" + certificatesCount + "): \n";
final String certDNs = Arrays.stream(certificates)
.map(X509Certificate::getSubjectDN)
.map(Principal::getName)
.map(SSLContextFactory::extractCommonName)
.collect(Collectors.joining(" |#| ", prefix, "\n"));
log.info(certDNs);
}
#VisibleForTesting
static String extractCommonName(String principalName) {
... Some code for extracting commonname from principal name...
return cn;
}
Where does the TrustManagerFactory find the pcf trusted certificates?
How can I check if those pcf certificates are available & loaded, or where can I get the pcf-certificates-only TrustManager. My worry is that it might cause issues if I load it twice, but I have no indication it is causing issues (but now I have 288 instead of 144 certificates in my SSLContext, does that impact performance? Can it cause issues?)).
Regards,
Rick
The Java buildpack adds a component called the Container Security Provider. This is what adds the functionality to automatically load Platform/Bosh trusted CA certificates, as well as the container instance ID cert and key.
To ensure platform/Bosh trusted CA certificates are trusted, the Container Security Provider adds a TrustManagerFactory. This looks at the file /etc/ssl/certs/ca-certificates.crt and trusts everything in that file.
This is in addition to the default behavior of the JVM.
I log the number of certificates it finds and I log the found CN's. However I found it list every certificate twice!
You didn't share the code to show how you're doing this, so I can only speculate. My suspicion is that you're seeing duplicates because the Container Security Provider does not replace the default behavior for trusting CA certs in the JVM, it adds an additional TrustManager.
Pair that with the fact that there is probably a lot of overlap between what's in /etc/ssl/certs/ca-certificates.crt and what's in the JVM's default trust store. I guess I could see there being duplicates.
If I provide a keystore with 1 certificate:
It will log that certificate + all environment certificates.
This further's my suspicion because when you override the default JVM truststore, it sounds like the duplicates go away. That would mean you're left with your custom truststore plus what's added by the CSP.
Where does the TrustManagerFactory find the pcf trusted certificates.
https://github.com/cloudfoundry/java-buildpack-security-provider/blob/main/src/main/java/org/cloudfoundry/security/CloudFoundryContainerTrustManagerFactory.java#L41
How can I check if those pcf certificates are available & loaded, or where can I get the pcf-certificates-only TrustManager. I want this to prevent loading the certificates twice.
Is there a larger problem here? I get what you're saying about seeing certificates listed twice, but is that actually causing a problem with your application? If so, please update your question and explain what is happening? That might help to provide some more context.
Aside from that:
You can disable the CSP. Set and env variable JBP_CONFIG_CONTAINER_SECURITY_PROVIDER='{trust_manager_enabled: false}'.
https://github.com/cloudfoundry/java-buildpack/blob/main/docs/framework-container_security_provider.md#security-provider
Do understand that by disabling this, your application will not automatically trust platform/Bosh deployed CA certificates. This could cause failures. For example, if your application is binding to a CF marketplace service that is using certificates signed by a CA that is distributed through the platform/Bosh trusted CA certificates.
You could do the opposite & set the default Java truststore to point to an empty keystore. You'd need to create an empty keystore, probably under your application, then set -Djavax.net.ssl.keyStore=/home/vcap/app/empty.jks (/home/vcap/app is the root of your application, change the rest to point to where you store the empty keystore file).
https://stackoverflow.com/a/2138670/1585136
If my suspicion is true, either of those would result in the duplicates going away.

Signing a jar with jarsigner using a PFX file

What I've done is the following:
Creating a ca.key and ca.cert
Creating a server.key and server.csr
Signing the CSR with the CA, creating a server.cert
Creating a pfx using the server.cert and server.key
All this using OpenSSL.
Now I want to sign a JAR file with this PFX file using jarsigner.
$ jarsigner -storetype pkcs12 -keystore certificate.pfx myJAR.jar my-alias
And I get:
jar signed.
Warning:
The signer's certificate chain is invalid. Reason: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
No -tsa or -tsacert is provided and this jar is not timestamped. Without a timestamp, users may not be able to validate this jar after the signer certificate's expiration date (2022-05-12) or after any future revocation date.
The signer certificate will expire on 2022-05-12.
I also get this when I verify the jar. I'm guessing that this is due to the fact that nothing tells the JRE to trust the CA that signed the certificate that signed this JAR, but I'm not sure. What is a certificate chain anyway?
Please help.
An X.509 certificate can be used for various purposes. The keyUsage and extendedKeyUsage extensions in the certificate identify what its intended uses are. When a certificate is issued with certain keyUsage's, you can only perform those cipher operations with its public key. If you are trying to do any other operation that is not supported, the library that is doing the cipher operation will complain so. You can find the standard key usages here.
A certificate that is to be used for code-signing purposes should contain the digitalSignature key usage. You can read more about this here.
So in your case, it is either one of these:
You didn't ask the CA to issue the certificate with digitalSignature keyUsage, (or)
If you see digitalSignature keyUsage added, then the CA is not configured properly to issue the digital signature certificate (probably missed to add the necessary attributes required).
If you are using a well-known CA, then you don't have to worry about the point (2), it will be taken care of and you can focus on point (1).
There are two ways to do that, if the CA is honoring the extensions from your CSR, then you need to add the digitalSignature extension in the keyUsage of your CSR (or) if the CA isn't honoring the extensions from your CSR, then you need to figure out how to ask the CA for a digitalSignature certificate.
A certificate is simply a trusting relation between two entities, the issuer (who sign on the certificate) and the subject.
Example:
Gov. of Merryland (Issuer) (Root-CA)
+ certificateA
+ Tot The Diplomatist (Subject)
+ certificateB (contains copy of certificateA in a chain)
+ Dot The Diplomatists Secretary
So we have a certificate chain. (Id painted this as a tree because on a certificate can theoretically be signed by multiple issuers).
Each certificates have the signature of one Issuer in this example:
The issuer of CertificateA is the Gov. of Merryland.
The issuer of CertificateB is Tot The Diplomatist.
Now assuming the Diplomatists Secretary arrives in Oogaboo showing its CertificateB (Having the CertificateA in the "Chain"). The Government of Oogaboo try to verify the authenticy of the Secretary using the "Chain" of the certificates.
What the message
unable to find valid certification path to requested target
sais is that Gov. of Oogaboo do not trust any of the Issuers.

NET::ERR_CERT_COMMON_NAME_INVALID security certificate does not specify Subject Alternative Names

I apologize if my english is not too good. I am trying to create a certificate request from my IIS server, but everytime i completed the request. The client still don't trust the web server.
I am from a development background not really into infrastructure operation. So my question might be incorrect, due to misconception, if so, please feel free to educate me. Below are my questions:
Do I need to import the root certificate into the window IIS server before starting a certificate request? If so, how do i create or export a root certificate from Window Certificate Authority?
Although this answer is not Windows-specific, I found this page through a search for my problem, and hopefully the following information will be of use to someone having this problem on Linux, like me:
I have encountered this problem too and, although the accepted answer is probably correct, the process for generating a CSR (certificate signing request) with the SAN (Subject Alternative Name) requires a bit of explanation.
There are several articles detailing this, but basically, you need to create a file, let's call it ssl.conf, which contains the necessary information, including the SAN details, which you will pass via a parameter to the openssl command when creating the CSR.
(This assumes you have already generated a key).
The contents of ssl.conf can be as simple as follows. Note the section at the bottom detailing the SAN. Adjust all the parameters to suit your requirements.
[req]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[ dn ]
C=US
ST=New York
L=Rochester
O=End Point
OU=Testing Domain
emailAddress=your-administrative-address#your-awesome-existing-domain.com
CN = www.your-new-domain.com
[ req_ext ]
subjectAltName = #alt_names
[ alt_names ]
DNS.1 = your-new-domain.com
DNS.2 = www.your-new-domain.com
The rest of the file contains other X.509 information that you would be prompted for during the CSR creation (country, state etc.)
Now you can create your CSR as follows:
openssl req -new -sha256 -out private.csr -key private.key -config ssl.conf
Where private.csr refers to your new CSR file, private.key refers to the key you already should have generated and ssl.conf is the file above.
You can verify the contents of your new CSR as follows:
openssl req -text -noout -verify -in private.csr
Then you will see, on the console, the details of the CSR, including the SAN details.
References:
https://www.endpoint.com/blog/2014/10/30/openssl-csr-with-alternative-names-one
https://gist.github.com/croxton/ebfb5f3ac143cd86542788f972434c96
https://geekflare.com/san-ssl-certificate/
The error can be because of multiple reasons
a) You are using an IP address to access the website (assuming you have a certificate based on a URL). So try accessing using the URL for which you have procured the certificate
b) You have procured certificate for xyz.com but have binded the same to abc.com . Hence when accessing abc.com you receive the above error. Bind the correct certificate if have one.
c) YOu have procured a multi domain certificate , but the url you are trying to access is not added as SAN to the certificate. Have a word with your SSL provider and ask him to add the URL as SAN to the certificate.
Should not the answer be that Subject Alternative Name (SAN) is mandated by Chrome for Certificate Validation check? Here is a link which speaks more about comparison between Common Name (CN) and SAN

Google API RS256 Key Signing

I wanted to implement Google's OAuth 2.0 Sever to Server process in Erlang/Elixir, but am having a bit of difficutly.
Primarily, I can't seem to find the public key that Google is using to verify my signature (at least this is what I think the problem is.
I've downloaded the JSON file that google provides which includes a "private_key" as well as a URL where I can find the "client_x509_certs". When I go to that link I even see an x509 certificate that has an identifier that corresponds to my private key. So how come I can't verify my signatures?
I mean first off, in order to make erlang happy I had to convert the private key to the RSA format using this command:
openssl rsa -in key.pem -out rsa.key
I was then able to sign things using Erlang's public_key.sign.
{ :ok, key } = File.read("./private_key")
[ key | _ ] = :public_key.pem_decode(key)
key = :public_key.pem_entry_decode(key)
sig = :public_key.sign("halloween", :sha256, key)
However, after extracting the RSA public key from the x509 certificates provided in the UR; I can't verify any of my signatures.
:public_key.verify("halloween", :sha256, sig, public_key)
Am I not getting my public key from the right place?

How to import an OpenSSL key file into the Windows Certificate Store

I've got an OpenSSL generated X.509 certificate in PEM format and it's associated key file. This certificate is required for authentication when connecting to a prototype server. This works fine on Linux. I've been using the Microsoft SChannel API to drive SSL/TLS connections on Windows platforms but I want to use the same test certificate. I can right-click on the certificate file and import it into my certificate store but I believe that the private key is not imported with it (even though I've concatenated them into the same file).
When I go to run the SChannel code, I get a 'SEC_E_NO_CREDENTIALS' error when I init the security context (via InitializeSecurityContext). I suspect this means that the private key is missing.
Does anyone know how to test the presence or absence of a private key in a certificate which is located in the Personal (or 'My') certificate store, accessed via 'certmgr.msc'?. Is it possible to import a new key file for a certificate in the store?
Any insight or advice would be much appreciated.
To test if private key is installed for the certificate, double click the certificate icon in certmgr.msc. If it has private key, it will show a message in the property page that you have private key, otherwise it will not give any reference the the private key.
To import the certificate with its private key, you can do the following:
Pack the certificate and its private key into a PKCS #12 file or PFX file using openssl pkcs12. Here's an example.
Import this PKCS #12 or PFX file into the certificate store.
Note that you may see errors when importing the pfx file, such as 'This file is invalid for use as the following: Personal Information Exchange'. This error was caused by the certificate lacking to appropriate X.509 v3 extensions (such as the usage fields (digital signature, etc))

Resources