org.apache.nifi.web.security.x509.ocsp.OcspCertificateValidatorTest.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.nifi.web.security.x509.ocsp.OcspCertificateValidatorTest.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.nifi.web.security.x509.ocsp;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Vector;

public class OcspCertificateValidatorTest {
    private static final Logger logger = LoggerFactory.getLogger(OcspCertificateValidatorTest.class);

    private static final int KEY_SIZE = 2048;

    private static final long YESTERDAY = System.currentTimeMillis() - 24 * 60 * 60 * 1000;
    private static final long ONE_YEAR_FROM_NOW = System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000;
    private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
    private static final String PROVIDER = "BC";

    private static final String ISSUER_DN = "CN=NiFi Test CA,OU=Security,O=Apache,ST=CA,C=US";

    private static X509Certificate ISSUER_CERTIFICATE;

    @BeforeClass
    public static void setUpOnce() throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        //        ISSUER_CERTIFICATE = generateCertificate(ISSUER_DN);
    }

    @Before
    public void setUp() throws Exception {
    }

    @After
    public void tearDown() throws Exception {

    }

    /**
     * Generates a public/private RSA keypair using the default key size.
     *
     * @return the keypair
     * @throws NoSuchAlgorithmException if the RSA algorithm is not available
     */
    private static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(KEY_SIZE);
        return keyPairGenerator.generateKeyPair();
    }

    /**
     * Generates a signed certificate using an on-demand keypair.
     *
     * @param dn the DN
     * @return the certificate
     * @throws IOException               if an exception occurs
     * @throws NoSuchAlgorithmException  if an exception occurs
     * @throws CertificateException      if an exception occurs
     * @throws NoSuchProviderException   if an exception occurs
     * @throws SignatureException        if an exception occurs
     * @throws InvalidKeyException       if an exception occurs
     * @throws OperatorCreationException if an exception occurs
     */
    private static X509Certificate generateCertificate(String dn)
            throws IOException, NoSuchAlgorithmException, CertificateException, NoSuchProviderException,
            SignatureException, InvalidKeyException, OperatorCreationException {
        KeyPair keyPair = generateKeyPair();
        return generateCertificate(dn, keyPair);
    }

    /**
     * Generates a signed certificate with a specific keypair.
     *
     * @param dn      the DN
     * @param keyPair the public key will be included in the certificate and the the private key is used to sign the certificate
     * @return the certificate
     * @throws IOException               if an exception occurs
     * @throws NoSuchAlgorithmException  if an exception occurs
     * @throws CertificateException      if an exception occurs
     * @throws NoSuchProviderException   if an exception occurs
     * @throws SignatureException        if an exception occurs
     * @throws InvalidKeyException       if an exception occurs
     * @throws OperatorCreationException if an exception occurs
     */
    private static X509Certificate generateCertificate(String dn, KeyPair keyPair)
            throws IOException, NoSuchAlgorithmException, CertificateException, NoSuchProviderException,
            SignatureException, InvalidKeyException, OperatorCreationException {
        PrivateKey privateKey = keyPair.getPrivate();
        ContentSigner sigGen = new JcaContentSignerBuilder(SIGNATURE_ALGORITHM).setProvider(PROVIDER)
                .build(privateKey);
        SubjectPublicKeyInfo subPubKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
        Date startDate = new Date(YESTERDAY);
        Date endDate = new Date(ONE_YEAR_FROM_NOW);

        X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(new X500Name(dn),
                BigInteger.valueOf(System.currentTimeMillis()), startDate, endDate, new X500Name(dn),
                subPubKeyInfo);

        // Set certificate extensions
        // (1) digitalSignature extension
        certBuilder.addExtension(X509Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature
                | KeyUsage.keyEncipherment | KeyUsage.dataEncipherment | KeyUsage.keyAgreement));

        // (2) extendedKeyUsage extension
        Vector<KeyPurposeId> ekUsages = new Vector<>();
        ekUsages.add(KeyPurposeId.id_kp_clientAuth);
        ekUsages.add(KeyPurposeId.id_kp_serverAuth);
        certBuilder.addExtension(X509Extension.extendedKeyUsage, false, new ExtendedKeyUsage(ekUsages));

        // Sign the certificate
        X509CertificateHolder certificateHolder = certBuilder.build(sigGen);
        return new JcaX509CertificateConverter().setProvider(PROVIDER).getCertificate(certificateHolder);
    }

    /**
     * Generates a certificate signed by the issuer key.
     *
     * @param dn        the subject DN
     * @param issuerDn  the issuer DN
     * @param issuerKey the issuer private key
     * @return the certificate
     * @throws IOException               if an exception occurs
     * @throws NoSuchAlgorithmException  if an exception occurs
     * @throws CertificateException      if an exception occurs
     * @throws NoSuchProviderException   if an exception occurs
     * @throws SignatureException        if an exception occurs
     * @throws InvalidKeyException       if an exception occurs
     * @throws OperatorCreationException if an exception occurs
     */
    private static X509Certificate generateIssuedCertificate(String dn, String issuerDn, PrivateKey issuerKey)
            throws IOException, NoSuchAlgorithmException, CertificateException, NoSuchProviderException,
            SignatureException, InvalidKeyException, OperatorCreationException {
        KeyPair keyPair = generateKeyPair();
        return generateIssuedCertificate(dn, keyPair.getPublic(), issuerDn, issuerKey);
    }

    /**
     * Generates a certificate with a specific public key signed by the issuer key.
     *
     * @param dn        the subject DN
     * @param publicKey the subject public key
     * @param issuerDn  the issuer DN
     * @param issuerKey the issuer private key
     * @return the certificate
     * @throws IOException               if an exception occurs
     * @throws NoSuchAlgorithmException  if an exception occurs
     * @throws CertificateException      if an exception occurs
     * @throws NoSuchProviderException   if an exception occurs
     * @throws SignatureException        if an exception occurs
     * @throws InvalidKeyException       if an exception occurs
     * @throws OperatorCreationException if an exception occurs
     */
    private static X509Certificate generateIssuedCertificate(String dn, PublicKey publicKey, String issuerDn,
            PrivateKey issuerKey) throws IOException, NoSuchAlgorithmException, CertificateException,
            NoSuchProviderException, SignatureException, InvalidKeyException, OperatorCreationException {
        ContentSigner sigGen = new JcaContentSignerBuilder(SIGNATURE_ALGORITHM).setProvider(PROVIDER)
                .build(issuerKey);
        SubjectPublicKeyInfo subPubKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
        Date startDate = new Date(YESTERDAY);
        Date endDate = new Date(ONE_YEAR_FROM_NOW);

        X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(new X500Name(issuerDn),
                BigInteger.valueOf(System.currentTimeMillis()), startDate, endDate, new X500Name(dn),
                subPubKeyInfo);

        X509CertificateHolder certificateHolder = v3CertGen.build(sigGen);
        return new JcaX509CertificateConverter().setProvider(PROVIDER).getCertificate(certificateHolder);
    }

    @Test
    public void testShouldGenerateCertificate() throws Exception {
        // Arrange
        final String testDn = "CN=This is a test";

        // Act
        X509Certificate certificate = generateCertificate(testDn);
        logger.info("Generated certificate: \n{}", certificate);

        // Assert
        assert certificate.getSubjectDN().getName().equals(testDn);
        assert certificate.getIssuerDN().getName().equals(testDn);
        certificate.verify(certificate.getPublicKey());
    }

    @Test
    public void testShouldGenerateCertificateFromKeyPair() throws Exception {
        // Arrange
        final String testDn = "CN=This is a test";
        final KeyPair keyPair = generateKeyPair();

        // Act
        X509Certificate certificate = generateCertificate(testDn, keyPair);
        logger.info("Generated certificate: \n{}", certificate);

        // Assert
        assert certificate.getPublicKey().equals(keyPair.getPublic());
        assert certificate.getSubjectDN().getName().equals(testDn);
        assert certificate.getIssuerDN().getName().equals(testDn);
        certificate.verify(certificate.getPublicKey());
    }

    @Test
    public void testShouldGenerateIssuedCertificate() throws Exception {
        // Arrange
        final String testDn = "CN=This is a signed test";
        final String issuerDn = "CN=Issuer CA";
        final KeyPair issuerKeyPair = generateKeyPair();
        final PrivateKey issuerPrivateKey = issuerKeyPair.getPrivate();

        final X509Certificate issuerCertificate = generateCertificate(issuerDn, issuerKeyPair);
        logger.info("Generated issuer certificate: \n{}", issuerCertificate);

        // Act
        X509Certificate certificate = generateIssuedCertificate(testDn, issuerDn, issuerPrivateKey);
        logger.info("Generated signed certificate: \n{}", certificate);

        // Assert
        assert issuerCertificate.getPublicKey().equals(issuerKeyPair.getPublic());
        assert certificate.getSubjectX500Principal().getName().equals(testDn);
        assert certificate.getIssuerX500Principal().getName().equals(issuerDn);
        certificate.verify(issuerCertificate.getPublicKey());

        try {
            certificate.verify(certificate.getPublicKey());
            Assert.fail("Should have thrown exception");
        } catch (Exception e) {
            assert e instanceof SignatureException;
            assert e.getMessage().contains("certificate does not verify with supplied key");
        }
    }

    @Ignore("To be implemented with Groovy test")
    @Test
    public void testShouldValidateCertificate() throws Exception {

    }

    @Ignore("To be implemented with Groovy test")
    @Test
    public void testShouldNotValidateEmptyCertificate() throws Exception {

    }

    @Ignore("To be implemented with Groovy test")
    @Test
    public void testShouldNotValidateInvalidCertificate() throws Exception {

    }

    @Ignore("To be implemented with Groovy test")
    @Test
    public void testValidateShouldHandleUnsignedResponse() throws Exception {

    }

    @Ignore("To be implemented with Groovy test")
    @Test
    public void testValidateShouldHandleResponseWithIncorrectNonce() throws Exception {

    }
}