Java tutorial
/************************************************************************* * 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; } }