0

I'm trying to verify the certificates provided by the users to my tomcat website (during mutual/client/certificate authentication).

Now I know that verifying the certificates manually may not be required as I suppose the browser does it before prompting for a certificate to the user. However, I still tried to do it and I have a few questions about it.

Please go through my process of creating the certificates as well as verifying them.

I am generating the Certificates as below:

# Generate Root Key
openssl genrsa -des3 -out root.key 2048

# Create a self signed Root Certificate
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out root.crt

# Generate User Key
openssl genrsa -out user.key 2048

# Generate User CSR
openssl req -new -key user.key -out user.csr

# Generate User Certificate and sign with Root Key
openssl x509 -req -in user.csr -CA root.crt -CAkey root.key -CAcreateserial -out user.crt -days 500 -sha256

Now I import the user.crt, user.key and the root.crt in a user.p12 keystore like so:

openssl pkcs12 -export -out user.p12 -inkey user.key -in user.cert -certfile root.crt

user.p12 gets distributed to the users who will be using the site.

I imported the root.crt to my "truststore" which is used by tomcat.

Now, when I try to verify the certificate provided by the users, I try to do the following:

File file = new File(keystorePath);
InputStream is = new FileInputStream(file);
keyStore.load(is, keyStorePass.toCharArray());

PKIXParameters params = new PKIXParameters(keyStore);

Set<TrustAnchor> trustAnchors = params.getTrustAnchors();

List<Certificate> certificates = trustAnchors.stream()
        .map(TrustAnchor::getTrustedCert)
        .collect(Collectors.toList());

Boolean certVerified = Boolean.FALSE;
for (Certificate cert : certificates){
    try {
        userCertificate.verify(cert.getPublicKey());
    } catch (Exception e) {
        e.printStackTrace();
        continue;
    }
    LOGGER.info("Verified User Certificate.");
    certVerified = Boolean.TRUE;
    break;
}

This seems to work fine. However, my question is that since user.crt is created with root.crt, shouldn't the following code:

userCertificate.verify(cert.getPublicKey());

work like this?

cert.verify(userCertificate.getPublicKey());

My questions are as follows:

  1. Am I correct in assuming that I do not need verify user certificates in my code?
  2. If the user.crt is created with root.crt, why is user.crt used to verify root.crt and not the other way round?
  3. Am I completely dense and missing something important and all my logic is incorrect?
  • 1
    1. The only thing you're verifying is user certificates. 2. `root.crt` *is* used to verify `user.crt`. 3. I think you're just reading the method wrong: `cert1.verify(cert2.getPublicKey())` means use `cert2` to verify `cert1`. See the [javadoc](https://docs.oracle.com/javase/8/docs/api/java/security/cert/Certificate.html#verify-java.security.PublicKey-). – Robby Cornelissen Jun 30 '22 at 06:57
  • 1. Yes you don't need to verify the client cert; the SSL/TLS implementation in your server already does, either the Java implementation JSSE if you configure that way, or OpenSSL if you (install and) configure 'native/APR'. That's the whole _point_ of SSL/TLS client authentication, namely that it authenticates the client. – dave_thompson_085 Jun 30 '22 at 10:10

0 Answers0