brooklyn.util.crypto.FluentKeySigner.java Source code

Java tutorial

Introduction

Here is the source code for brooklyn.util.crypto.FluentKeySigner.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 brooklyn.util.crypto;

import java.math.BigInteger;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.Date;

import javax.security.auth.x500.X500Principal;

import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.asn1.x509.X509Name;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;

import brooklyn.util.exceptions.Exceptions;

/** A fluent API which simplifies generating certificates (signed keys) */
/* we use deprecated X509V3CertificateGenerator for now because official replacement,
 * X509v3CertificateBuilder drags in an add'l dependency (bcmail) and is harder to use. */
@SuppressWarnings("deprecation")
public class FluentKeySigner {

    protected X500Principal issuerPrincipal;
    protected KeyPair issuerKey;

    protected SecureRandom srand = new SecureRandom();

    protected Date validityStartDate, validityEndDate;
    protected BigInteger serialNumber;

    protected String signatureAlgorithm = "MD5WithRSAEncryption";
    protected AuthorityKeyIdentifierStructure authorityKeyIdentifier;
    protected X509Certificate authorityCertificate;

    public FluentKeySigner(X500Principal issuerPrincipal, KeyPair issuerKey) {
        this.issuerPrincipal = issuerPrincipal;
        this.issuerKey = issuerKey;
        validFromDaysAgo(7);
        validForYears(10);
    }

    public FluentKeySigner(String issuerCommonName, KeyPair issuerKey) {
        this(SecureKeys.getX500PrincipalWithCommonName(issuerCommonName), issuerKey);
    }

    public FluentKeySigner(String issuerCommonName) {
        this(issuerCommonName, SecureKeys.newKeyPair());
    }

    public FluentKeySigner(X509Certificate caCert, KeyPair caKey) {
        this(caCert.getIssuerX500Principal(), caKey);
        authorityCertificate(caCert);
    }

    public KeyPair getKey() {
        return issuerKey;
    }

    public X500Principal getPrincipal() {
        return issuerPrincipal;
    }

    public String getCommonName() {
        return (String) new X509Principal(issuerPrincipal.getName()).getValues(X509Name.CN).elementAt(0);
    }

    public X509Certificate getAuthorityCertificate() {
        return authorityCertificate;
    }

    public FluentKeySigner validFromDaysAgo(long days) {
        return validFrom(
                new Date((System.currentTimeMillis() / (1000L * 60 * 60 * 24) - days) * 1000L * 60 * 60 * 24));
    }

    public FluentKeySigner validFrom(Date d) {
        validityStartDate = d;
        return this;
    }

    public FluentKeySigner validForYears(long years) {
        return validUntil(new Date(
                (System.currentTimeMillis() / (1000L * 60 * 60 * 24) + 365 * years) * 1000L * 60 * 60 * 24));
    }

    public FluentKeySigner validUntil(Date d) {
        validityEndDate = d;
        return this;
    }

    /** use a hard-coded serial number; or make one up, if null */
    public FluentKeySigner serialNumber(BigInteger serialNumber) {
        this.serialNumber = serialNumber;
        return this;
    }

    public FluentKeySigner signatureAlgorithm(String signatureAlgorithm) {
        this.signatureAlgorithm = signatureAlgorithm;
        return this;
    }

    public FluentKeySigner authorityCertificate(X509Certificate certificate) {
        try {
            authorityKeyIdentifier(new AuthorityKeyIdentifierStructure(certificate));
            this.authorityCertificate = certificate;
            return this;
        } catch (CertificateParsingException e) {
            throw Exceptions.propagate(e);
        }
    }

    public FluentKeySigner authorityKeyIdentifier(AuthorityKeyIdentifierStructure authorityKeyIdentifier) {
        this.authorityKeyIdentifier = authorityKeyIdentifier;
        return this;
    }

    public FluentKeySigner selfsign() {
        if (authorityCertificate != null)
            throw new IllegalStateException("Signer already has certificate");
        authorityCertificate(newCertificateFor(getCommonName(), getKey()));
        return this;
    }

    public X509Certificate newCertificateFor(X500Principal subject, PublicKey keyToCertify) {
        try {
            X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();

            v3CertGen.setSerialNumber(serialNumber != null ? serialNumber :
            // must be positive
                    BigInteger.valueOf(srand.nextLong()).abs().add(BigInteger.ONE));
            v3CertGen.setIssuerDN(issuerPrincipal);
            v3CertGen.setNotBefore(validityStartDate);
            v3CertGen.setNotAfter(validityEndDate);
            v3CertGen.setSignatureAlgorithm(signatureAlgorithm);

            v3CertGen.setSubjectDN(subject);
            v3CertGen.setPublicKey(keyToCertify);

            v3CertGen.addExtension(X509Extension.subjectKeyIdentifier, false,
                    new SubjectKeyIdentifierStructure(keyToCertify));

            if (authorityKeyIdentifier != null)
                v3CertGen.addExtension(X509Extension.authorityKeyIdentifier, false, authorityKeyIdentifier);

            X509Certificate pkCertificate = v3CertGen.generate(issuerKey.getPrivate(), "BC");
            return pkCertificate;

        } catch (Exception e) {
            throw Exceptions.propagate(e);
        }
    }

    public X509Certificate newCertificateFor(String commonName, PublicKey key) {
        //        SecureKeys.getX509PrincipalWithCommonName(commonName)
        return newCertificateFor(SecureKeys.getX500PrincipalWithCommonName(commonName)
        //                new X509Principal("CN=" + commonName + ", OU=None, O=None, L=None, C=None")
                , key);
    }

    public X509Certificate newCertificateFor(String commonName, KeyPair key) {
        return newCertificateFor(commonName, key.getPublic());
    }

}