/* * Copyright (C) 2014 Intel Corporation * All rights reserved. */ package com.intel.mtwilson.trustagent.setup; import com.intel.dcsg.cpg.crypto.RsaCredentialX509; import com.intel.dcsg.cpg.crypto.RsaUtil; import com.intel.dcsg.cpg.crypto.SimpleKeystore; import com.intel.dcsg.cpg.io.FileResource; import com.intel.dcsg.cpg.x509.X509Builder; import com.intel.mtwilson.setup.AbstractSetupTask; import com.intel.mtwilson.trustagent.TrustagentConfiguration; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyPair; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.StringUtils; /** * * @author jbuhacoff */ public class CreateTlsKeypair extends AbstractSetupTask { private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CreateTlsKeypair.class); private TrustagentConfiguration trustagentConfiguration; private static final String TLS_ALIAS = "tls"; private String dn; private String[] ip; private String[] dns; @Override protected void configure() throws Exception { trustagentConfiguration = new TrustagentConfiguration(getConfiguration()); dn = trustagentConfiguration.getTrustagentTlsCertDn(); String keystorePassword = trustagentConfiguration.getTrustagentKeystorePassword(); // we need to know our own local ip addresses/hostname in order to add them to the ssl cert ip = trustagentConfiguration.getTrustagentTlsCertIpArray(); dns = trustagentConfiguration.getTrustagentTlsCertDnsArray(); if( dn == null || dn.isEmpty() ) { configuration("DN not configured"); } if( keystorePassword == null || keystorePassword.isEmpty() ) { configuration("Keystore password has not been generated"); } // NOTE: keystore file itself does not need to be checked, we will create it automatically in execute() if it does not exist if( (ip == null ? 0 : ip.length) + (dns == null ? 0 : dns.length) == 0 ) { configuration("At least one IP or DNS alternative name must be configured"); } } @Override protected void validate() throws Exception { File keystoreFile = trustagentConfiguration.getTrustagentKeystoreFile(); if( !keystoreFile.exists() ) { validation("Keystore file was not created"); return; } String keystorePassword = trustagentConfiguration.getTrustagentKeystorePassword(); SimpleKeystore keystore = new SimpleKeystore(new FileResource(keystoreFile), keystorePassword); RsaCredentialX509 credential; try { credential = keystore.getRsaCredentialX509(TLS_ALIAS, keystorePassword); log.debug("Found TLS key {}", credential.getCertificate().getSubjectX500Principal().getName()); } catch (FileNotFoundException e) { log.warn("Keystore does not contain the specified key [{}]", TLS_ALIAS); validation("Keystore does not contain the specified key %s", TLS_ALIAS); return; } catch(java.security.UnrecoverableKeyException e) { log.debug("Incorrect password for existing key; will create new key: {}", e.getMessage()); validation("Key must be recreated"); return; } catch(NullPointerException e) { log.debug("Invalid TLS certificate"); validation("Certificate must be recreated"); return; } // log.debug("credential {}", credential); // log.debug("credential certificate {}", credential.getCertificate()); // log.debug("credential certificate encoded {}", credential.getCertificate().getEncoded()); // log.debug("credential certificate encoded sha1 {}", Sha1Digest.digestOf(credential.getCertificate().getEncoded())); // log.debug("Keystore contains TLS keypair: ", Sha1Digest.digestOf(credential.getCertificate().getEncoded()).toHexString()); /* * Issue #2141 thi if( !dn.equals(credential.getCertificate().getSubjectX500Principal().getName()) ) { log.debug("Certificate DN not the same as configured DN; should recreate certificate"); validation("Configured DN does not match certificate DN; should recreate certificate"); } */ } @Override protected void execute() throws Exception { File keystoreFile = trustagentConfiguration.getTrustagentKeystoreFile(); String keystorePassword = trustagentConfiguration.getTrustagentKeystorePassword(); // create the keypair KeyPair keypair = RsaUtil.generateRsaKeyPair(2048); X509Builder builder = X509Builder.factory() .selfSigned(dn, keypair) .expires(3650, TimeUnit.DAYS) .keyUsageKeyEncipherment(); // NOTE: right now we are creating a self-signed cert but if we have // the mtwilson api url, username, and password, we could submit // a certificate signing request there and have our cert signed // by mtwilson's ca, and then the ssl policy for this host in // mtwilson could be "signed by trusted ca" instead of // "that specific cert" if( ip != null ) { for(String san : ip) { log.debug("Adding Subject Alternative Name (SAN) with IP address: {}", san); builder.ipAlternativeName(san.trim()); } } if( dns != null ) { for(String san : dns) { log.debug("Adding Subject Alternative Name (SAN) with Domain Name: {}", san); builder.dnsAlternativeName(san.trim()); } } X509Certificate tlscert = builder.build(); // look for an existing tls keypair and delete it SimpleKeystore keystore = new SimpleKeystore(new FileResource(keystoreFile), keystorePassword); try { // String alias = String.format("%s (ssl)", TLS_ALIAS); String alias = TLS_ALIAS; List<String> aliases = Arrays.asList(keystore.aliases()); if( aliases.contains(alias) ) { keystore.delete(alias); } } catch(KeyStoreException | KeyManagementException e) { log.debug("Cannot remove existing tls keypair", e); } // store it in the keystore keystore.addKeyPairX509(keypair.getPrivate(), tlscert, TLS_ALIAS, keystorePassword); keystore.save(); // save the settings in configuration getConfiguration().setString(TrustagentConfiguration.TRUSTAGENT_TLS_CERT_DN, dn); if( ip != null ) { getConfiguration().setString(TrustagentConfiguration.TRUSTAGENT_TLS_CERT_IP, StringUtils.join(ip, ",")); } if( dns != null ) { getConfiguration().setString(TrustagentConfiguration.TRUSTAGENT_TLS_CERT_DNS, StringUtils.join(dns, ",")); } } }