com.eucalyptus.auth.euare.EuareServerCertificateUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.eucalyptus.auth.euare.EuareServerCertificateUtil.java

Source

/*************************************************************************
 * Copyright 2009-2015 Eucalyptus Systems, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses/.
 *
 * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
 * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
 * additional information or have any questions.
 ************************************************************************/
package com.eucalyptus.auth.euare;

import java.security.MessageDigest;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.util.Calendar;
import java.util.Date;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.security.auth.x500.X500Principal;

import org.apache.commons.lang.time.DateUtils;
import org.apache.log4j.Logger;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Base64;

import com.eucalyptus.auth.AuthException;
import com.eucalyptus.auth.ServerCertificate;
import com.eucalyptus.auth.euare.principal.EuareAccount;
import com.eucalyptus.component.auth.SystemCredentials;
import com.eucalyptus.component.auth.SystemCredentials.Credentials;
import com.eucalyptus.component.id.Euare;
import com.eucalyptus.crypto.Certs;
import com.eucalyptus.crypto.Ciphers;
import com.eucalyptus.crypto.Crypto;
import com.eucalyptus.crypto.Digest;
import com.eucalyptus.crypto.util.B64;
import com.eucalyptus.crypto.util.PEMFiles;
import com.eucalyptus.util.Exceptions;

/**
 * @author Sang-Min Park
 *
 */
public class EuareServerCertificateUtil {
    private static Logger LOG = Logger.getLogger(EuareServerCertificateUtil.class);

    // return body and chain of server certificate in plain text
    public static String getServerCertificate(final String certArn) throws AuthException {
        final ServerCertificate targetCert = lookupServerCertificate(certArn);
        String serverCert = targetCert.getCertificateBody();
        final String chain = targetCert.getCertificateChain();
        if (chain != null && chain.length() > 0)
            serverCert = String.format("%s\n%s", serverCert, chain);

        return serverCert;
    }

    public static String getEncryptedKey(final String certArn, final String certPem) throws AuthException {
        final ServerCertificate targetCert = lookupServerCertificate(certArn);
        // generate symmetric key
        final MessageDigest digest = Digest.SHA256.get();
        final byte[] salt = new byte[32];
        Crypto.getSecureRandomSupplier().get().nextBytes(salt);
        digest.update(salt);
        final SecretKey symmKey = new SecretKeySpec(digest.digest(), "AES");

        try {
            // encrypt the server pk using symm key
            Cipher cipher = Ciphers.AES_CBC.get();
            final byte[] iv = new byte[16];
            Crypto.getSecureRandomSupplier().get().nextBytes(iv);
            cipher.init(Cipher.ENCRYPT_MODE, symmKey, new IvParameterSpec(iv),
                    Crypto.getSecureRandomSupplier().get());
            final byte[] cipherText = cipher.doFinal(Base64.encode(targetCert.getPrivateKey().getBytes()));
            final String encPrivKey = new String(Base64.encode(Arrays.concatenate(iv, cipherText)));

            // encrypt the symmetric key using the certPem
            X509Certificate x509Cert = PEMFiles.getCert(B64.standard.dec(certPem));
            cipher = Ciphers.RSA_PKCS1.get();
            cipher.init(Cipher.ENCRYPT_MODE, x509Cert.getPublicKey(), Crypto.getSecureRandomSupplier().get());
            byte[] symmkey = cipher.doFinal(symmKey.getEncoded());
            final String b64SymKey = new String(Base64.encode(symmkey));

            return String.format("%s\n%s", b64SymKey, encPrivKey);
        } catch (final Exception ex) {
            throw Exceptions.toUndeclared(ex);
        }
    }

    public static X509Certificate generateVMCertificate(final RSAPublicKey publicKey, final String principal,
            final int expirationDays) throws AuthException {
        try {
            final X500Principal subjectDn = new X500Principal(principal);
            final Credentials euareCred = SystemCredentials.lookup(Euare.class);
            final Principal signer = euareCred.getCertificate().getSubjectDN();
            final PrivateKey signingKey = euareCred.getPrivateKey();
            final Date notAfter = DateUtils.addDays(Calendar.getInstance().getTime(), expirationDays);
            final X509Certificate cert = Certs.generateCertificate(publicKey, subjectDn,
                    new X500Principal(signer.getName()), signingKey, notAfter);
            if (cert == null) {
                throw new Exception("Null returned");
            }
            return cert;
        } catch (final Exception ex) {
            throw new AuthException("failed to generate VM certificate", ex);
        }
    }

    public static String generateSignatureWithEuare(final String msg) {
        return generateSignature(SystemCredentials.lookup(Euare.class).getPrivateKey(), msg);
    }

    public static String generateSignature(final PrivateKey key, final String msg) {
        try {
            final Signature sig = Signature.getInstance("SHA256withRSA");
            sig.initSign(key);
            sig.update(msg.getBytes("UTF-8"));
            final byte[] bsig = sig.sign();
            return B64.standard.encString(bsig);
        } catch (final Exception ex) {
            throw Exceptions.toUndeclared(ex);
        }
    }

    public static boolean verifyCertificate(final String certPem, final boolean checkSigner) {
        try {
            final X509Certificate cert = PEMFiles.getCert(B64.standard.dec(certPem));
            cert.checkValidity();
            if (checkSigner) {
                final Credentials euareCred = SystemCredentials.lookup(Euare.class);
                final X509Certificate signer = euareCred.getCertificate();
                cert.verify(signer.getPublicKey());
            }
            return true;
        } catch (final Exception ex) {
            return false;
        }
    }

    public static boolean verifySignature(final String certPem, final String msg, final String sigB64) {
        try {
            final Signature sig = Signature.getInstance("SHA256withRSA");
            final X509Certificate cert = PEMFiles.getCert(B64.standard.dec(certPem));
            sig.initVerify(cert);
            sig.update(msg.getBytes("UTF-8"));
            return sig.verify(B64.standard.dec(sigB64.getBytes()));
        } catch (final Exception ex) {
            throw Exceptions.toUndeclared(ex);
        }
    }

    public static boolean verifySignatureWithEuare(final String msg, final String sigB64) {
        final String euareCert = B64.standard
                .encString(PEMFiles.getBytes(SystemCredentials.lookup(Euare.class).getCertificate()));
        return verifySignature(euareCert, msg, sigB64);
    }

    private static ServerCertificate lookupServerCertificate(final String certArn) throws AuthException {
        if (!certArn.startsWith("arn:aws:iam::"))
            Exceptions.toUndeclared(new Exception("ARN is not in valid format"));

        String arn = certArn;
        arn = arn.replace("arn:aws:iam::", "");
        final int idx = arn.indexOf(":server-certificate");
        if (idx <= 0) {
            Exceptions.toUndeclared(new Exception("ARN is not in valid format"));
        }
        final String acctId = arn.substring(0, idx);

        final EuareAccount owner = com.eucalyptus.auth.euare.Accounts.lookupAccountById(acctId);
        final String prefix = String.format("arn:aws:iam::%s:server-certificate", acctId);
        if (!certArn.startsWith(prefix))
            throw new AuthException(AuthException.SERVER_CERT_NO_SUCH_ENTITY);

        final String pathAndName = certArn.replace(prefix, "");
        final String certName = pathAndName.substring(pathAndName.lastIndexOf("/") + 1);

        final ServerCertificate targetCert = owner.lookupServerCertificate(certName);
        if (targetCert == null)
            throw new AuthException(AuthException.SERVER_CERT_NO_SUCH_ENTITY);
        return targetCert;
    }
}