Package org.candlepin.pki.impl

Source Code of org.candlepin.pki.impl.BouncyCastlePKIUtility

/**
* Copyright (c) 2009 - 2012 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package org.candlepin.pki.impl;

import org.candlepin.pki.PKIReader;
import org.candlepin.pki.PKIUtility;
import org.candlepin.pki.SubjectKeyIdentifierWriter;
import org.candlepin.pki.X509ByteExtensionWrapper;
import org.candlepin.pki.X509CRLEntryWrapper;
import org.candlepin.pki.X509ExtensionWrapper;
import org.candlepin.util.Util;

import com.google.inject.Inject;

import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.misc.NetscapeCertType;
import org.bouncycastle.asn1.x509.CRLNumber;
import org.bouncycastle.asn1.x509.CRLReason;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.openssl.PEMWriter;
import org.bouncycastle.x509.X509V2CRLGenerator;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyPair;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.security.auth.x500.X500Principal;

/**
* The default {@link PKIUtility} for Candlepin.
* This class implements methods to create X509 Certificates, X509 CRLs, encode
* objects in PEM format (for saving to the db or sending to the client), and
* decode raw ASN.1 DER values (as read from a Certificate/CRL).
*
* All code that imports bouncycastle should live either in this module,
* or in {@link BouncyCastlePKIReader}
*
* (March 24, 2011) Notes on implementing a PKIUtility with NSS/JSS:
*
* JSS provides classes and functions to generate X509Certificates (see CertificateInfo,
* for example).
*
* PEM encoding requires us to determine the object type (which we know), add the correct
* header and footer to the output, base64 encode the DER for the object, and line wrap
* the base64 encoding.
*
* decodeDERValue should be simple, as JSS provides code to parse ASN.1, but I wasn't
* able to get it to work.
*
* The big one is CRL generation. JSS has no code to generate CRLs in any format. We'll
* have to use the raw ASN.1 libraries to build up our own properly formatted CRL DER
* representation, then PEM encode it.
*
* See also {@link BouncyCastlePKIReader} for more notes on using NSS/JSS, and a note
* about not using bouncycastle as the JSSE provider.
*/
@SuppressWarnings("deprecation")
public class BouncyCastlePKIUtility extends PKIUtility {
    private static Logger log = LoggerFactory.getLogger(BouncyCastlePKIUtility.class);

    @Inject
    public BouncyCastlePKIUtility(PKIReader reader,
        SubjectKeyIdentifierWriter subjectKeyWriter) {
        super(reader, subjectKeyWriter);
    }

    @Override
    public X509Certificate createX509Certificate(String dn,
        Set<X509ExtensionWrapper> extensions, Set<X509ByteExtensionWrapper> byteExtensions,
        Date startDate, Date endDate,
        KeyPair clientKeyPair, BigInteger serialNumber, String alternateName)
        throws GeneralSecurityException, IOException {

        X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
        X509Certificate caCert = reader.getCACert();
        // set cert fields
        certGen.setSerialNumber(serialNumber);
        certGen.setIssuerDN(caCert.getSubjectX500Principal());
        certGen.setNotBefore(startDate);
        certGen.setNotAfter(endDate);

        X500Principal subjectPrincipal = new X500Principal(dn);
        certGen.setSubjectDN(subjectPrincipal);
        certGen.setPublicKey(clientKeyPair.getPublic());
        certGen.setSignatureAlgorithm(SIGNATURE_ALGO);

        // set key usage - required for proper x509 function
        KeyUsage keyUsage = new KeyUsage(KeyUsage.digitalSignature |
            KeyUsage.keyEncipherment | KeyUsage.dataEncipherment);

        // add SSL extensions - required for proper x509 function
        NetscapeCertType certType = new NetscapeCertType(
            NetscapeCertType.sslClient | NetscapeCertType.smime);

        certGen.addExtension(MiscObjectIdentifiers.netscapeCertType.toString(),
            false, certType);
        certGen.addExtension(X509Extensions.KeyUsage.toString(), false,
            keyUsage);

        certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
            new AuthorityKeyIdentifierStructure(caCert));
        certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
              subjectKeyWriter.getSubjectKeyIdentifier(clientKeyPair, extensions));
        certGen.addExtension(X509Extensions.ExtendedKeyUsage, false,
            new ExtendedKeyUsage(KeyPurposeId.id_kp_clientAuth));

        // Add an alternate name if provided
        if (alternateName != null) {
            GeneralName name = new GeneralName(GeneralName.uniformResourceIdentifier,
                "CN=" + alternateName);
            certGen.addExtension(X509Extensions.SubjectAlternativeName, false,
                new GeneralNames(name));
        }

        if (extensions != null) {
            for (X509ExtensionWrapper wrapper : extensions) {
                // Bouncycastle hates null values. So, set them to blank
                // if they are null
                String value = wrapper.getValue() == null ? "" :  wrapper.getValue();
                certGen.addExtension(wrapper.getOid(), wrapper.isCritical(),
                    new DERUTF8String(value));
            }
        }

        if (byteExtensions != null) {
            for (X509ByteExtensionWrapper wrapper : byteExtensions) {
                // Bouncycastle hates null values. So, set them to blank
                // if they are null
                byte[] value = wrapper.getValue() == null ? new byte[0] :
                    wrapper.getValue();
                certGen.addExtension(wrapper.getOid(), wrapper.isCritical(),
                    new DEROctetString(value));
            }
        }

        // Generate the certificate
        return certGen.generate(reader.getCaKey());
    }

    @Override
    public X509CRL createX509CRL(List<X509CRLEntryWrapper> entries, BigInteger crlNumber) {

        try {
            X509Certificate caCert = reader.getCACert();
            X509V2CRLGenerator generator = new X509V2CRLGenerator();
            generator.setIssuerDN(caCert.getIssuerX500Principal());
            generator.setThisUpdate(new Date());
            generator.setNextUpdate(Util.tomorrow());
            generator.setSignatureAlgorithm(SIGNATURE_ALGO);
            // add all the CRL entries.
            for (X509CRLEntryWrapper entry : entries) {
                generator.addCRLEntry(entry.getSerialNumber(), entry.getRevocationDate(),
                    CRLReason.privilegeWithdrawn);
            }
            log.info("Completed adding CRL numbers to the certificate.");
            generator.addExtension(X509Extensions.AuthorityKeyIdentifier,
                false, new AuthorityKeyIdentifierStructure(caCert));
            generator.addExtension(X509Extensions.CRLNumber, false,
                new CRLNumber(crlNumber));
            return generator.generate(reader.getCaKey());
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private byte[] getPemEncoded(Object obj) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        OutputStreamWriter oswriter = new OutputStreamWriter(byteArrayOutputStream);
        PEMWriter writer = new PEMWriter(oswriter);
        writer.writeObject(obj);
        writer.close();
        return byteArrayOutputStream.toByteArray();
    }

    @Override
    public byte[] getPemEncoded(X509Certificate cert) throws IOException {
        return getPemEncoded((Object) cert);
    }

    @Override
    public byte[] getPemEncoded(Key key) throws IOException {
        return getPemEncoded((Object) key);
    }

    @Override
    public byte[] getPemEncoded(X509CRL crl) throws IOException {
        return getPemEncoded((Object) crl);
    }

    @Override
    public String decodeDERValue(byte[] value) {
        ASN1InputStream vis = null;
        ASN1InputStream decoded = null;
        try {
            vis = new ASN1InputStream(value);
            decoded = new ASN1InputStream(
                ((DEROctetString) vis.readObject()).getOctets());

            return decoded.readObject().toString();
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }
        finally {
            if (vis != null) {
                try {
                    vis.close();
                }
                catch (IOException e) {
                    log.warn("failed to close ASN1 stream", e);
                }
            }

            if (decoded != null) {
                try {
                    decoded.close();
                }
                catch (IOException e) {
                    log.warn("failed to close ASN1 stream", e);
                }
            }
        }
    }
}
TOP

Related Classes of org.candlepin.pki.impl.BouncyCastlePKIUtility

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.