/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.intel.mtwilson.agent.citrix;
//import java.lang.Process;
import com.intel.mountwilson.as.common.ASConfig;
import com.intel.mountwilson.as.common.ASException;
import com.intel.mountwilson.as.helper.CommandUtil;
import com.intel.mountwilson.ta.data.hostinfo.HostInfo;
import com.intel.mtwilson.datatypes.ConnectionString;
import com.intel.mtwilson.i18n.ErrorCode;
import com.intel.mtwilson.model.Pcr;
import com.intel.mtwilson.model.PcrIndex;
import com.intel.dcsg.cpg.crypto.Sha1Digest;
import com.intel.dcsg.cpg.io.Platform;
import com.intel.dcsg.cpg.tls.policy.TlsConnection;
import com.intel.dcsg.cpg.tls.policy.TlsUtil;
import com.intel.mtwilson.MyFilesystem;
import com.xensource.xenapi.APIVersion;
import com.xensource.xenapi.Connection;
import com.xensource.xenapi.Host;
import com.xensource.xenapi.Session;
import com.xensource.xenapi.Types.BadServerResponse;
import com.xensource.xenapi.Types.XenAPIException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.configuration.Configuration;
import org.apache.xmlrpc.XmlRpcException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author stdalex
*/
public class CitrixClient {
private transient Logger log = LoggerFactory.getLogger(getClass());
String hostIpAddress;
int port;
String userName;
String password;
String connectionString;
// private String aikverifyhome;
private String aikverifyhomeData;
private String aikverifyhomeBin;
private String opensslCmd;
private String aikverifyCmd;
private TlsConnection tlsConnection;
private Pattern pcrNumberPattern = Pattern.compile("[0-9]|[0-1][0-9]|2[0-3]"); // integer 0-23 with optional zero-padding (00, 01, ...)
private Pattern pcrValuePattern = Pattern.compile("[0-9a-fA-F]{40}"); // 40-character hex string
private String pcrNumberUntaint = "[^0-9]";
private String pcrValueUntaint = "[^0-9a-fA-F]";
private String AIKCert = null;
protected Connection connection;
public CitrixClient(TlsConnection tlsConnection) {
this.tlsConnection = tlsConnection;
this.connectionString = tlsConnection.getURL().toExternalForm();
// log.info("CitrixClient connectionString == " + connectionString);
// connectionString == citrix:https://xenserver:port;username;password or citrix:https://xenserver:port;u=username;p=password or the same w/o the citrix prefix
try {
ConnectionString.CitrixConnectionString citrixConnection = ConnectionString.CitrixConnectionString.forURL(connectionString);
hostIpAddress = citrixConnection.getHost().toString();
port = citrixConnection.getPort();
userName = citrixConnection.getUsername();
password = citrixConnection.getPassword();
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Invalid Citrix Host URL", e); // NOTE: we are NOT providing the connection string in the error message because, since we can't parse it, we dn't know if there's a password in there.
}
//log.info("stdalex-error citrixInit IP:" + hostIpAddress + " port:" + port + " user: " + userName + " pw:" + password);
// check mtwilson 2.0 configuration first
String binPath = MyFilesystem.getApplicationFilesystem().getBootstrapFilesystem().getBinPath();
String varPath = MyFilesystem.getApplicationFilesystem().getBootstrapFilesystem().getVarPath() + File.separator + "aikqverify";
log.debug("binpath = {}", binPath);
log.debug("varpath = {}", varPath);
File bin = new File(binPath);
File var = new File(varPath);
if (bin.exists() && var.exists()) {
aikverifyhomeBin = binPath;
aikverifyhomeData = varPath;
opensslCmd = aikverifyhomeBin + File.separator + (Platform.isUnix() ? "openssl" : "openssl.bat"); //My.configuration().getConfiguration().getString("com.intel.mountwilson.as.openssl.cmd", "openssl.bat"));
aikverifyCmd = aikverifyhomeBin + File.separator + (Platform.isUnix() ? "aikqverify" : "aikqverify.exe");
} else {
// mtwilson 1.2 configuration
Configuration config = ASConfig.getConfiguration();
String aikverifyhome = config.getString("com.intel.mountwilson.as.home", "C:/work/aikverifyhome");
aikverifyhomeData = aikverifyhome + File.separator + "data";
aikverifyhomeBin = aikverifyhome + File.separator + "bin";
opensslCmd = aikverifyhomeBin + File.separator + config.getString("com.intel.mountwilson.as.openssl.cmd", "openssl.bat");
aikverifyCmd = aikverifyhomeBin + File.separator + config.getString("com.intel.mountwilson.as.aikqverify.cmd", "aikqverify.exe");
}
}
public void init() {
boolean foundAllRequiredFiles = true;
String required[] = new String[]{opensslCmd, aikverifyCmd, aikverifyhomeData};
for (String filename : required) {
File file = new File(filename);
if (!file.exists()) {
log.debug(String.format("Invalid service configuration: Cannot find %s", filename));
foundAllRequiredFiles = false;
}
}
if (!foundAllRequiredFiles) {
throw new ASException(ErrorCode.AS_CONFIGURATION_ERROR, "Cannot find aikverify files");
}
// we must be able to write to the data folder in order to save certificates, nones, public keys, etc.
//log.info("stdalex-error checking to see if we can write to " + aikverifyhomeData);
File datafolder = new File(aikverifyhomeData);
if (!datafolder.canWrite()) {
throw new ASException(ErrorCode.AS_CONFIGURATION_ERROR, String.format(" Cannot write to %s", aikverifyhomeData));
}
}
// Commenting the below function since it is not being used and klocwork is throwing a warning
/*private String removeTags(String xml) {
String resp = "";
int i = 0;
for(; i < xml.length(); i++) {
if(xml.charAt(i) == '>') {
i++;
break;
}
}
for(;i < xml.length(); i++) {
if(xml.charAt(i) == '<'){
break;
}
resp += xml.charAt(i);
}
return resp;
}*/
public class keys {
public String tpmEndCert;
public String tpmEndKeyPEM;
public String tpmAttKeyPEM;
public String tpmAttKeyTCPA;
public keys() {
}
}
public void connect() throws NoSuchAlgorithmException, KeyManagementException, BadServerResponse, XenAPIException, XmlRpcException, XmlRpcException {
URL url;
try {
url = new URL("https://" + hostIpAddress + ":" + port);
} catch (MalformedURLException e) {
throw new ASException(e, ErrorCode.AS_HOST_COMMUNICATION_ERROR, hostIpAddress);
}
// TrustManager[] trustAllCerts = new TrustManager[]{tlsConnection.getTlsPolicy().getTrustManager()};
log.debug("Connecting to Citrix with ProtocolSelector: {}", tlsConnection.getTlsPolicy().getProtocolSelector().preferred());
// SSLContext sc = SSLContext.getInstance(tlsConnection.getTlsPolicy().getProtocolSelector().preferred()); // issue #871 ssl protocol should be configurable; was hardcoded to "SSL" before
// sc.init(null, trustAllCerts, new java.security.SecureRandom());
// HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// HttpsURLConnection.setDefaultHostnameVerifier(tlsConnection.getTlsPolicy().getHostnameVerifier());
// it would be better to use TlsConnection's openConnection directly but the URL is used from Citrix code so we try to affect it by setting the default policies
TlsUtil.setHttpsURLConnectionDefaults(tlsConnection);
connection = new Connection(url);
Session.loginWithPassword(connection, userName, password, APIVersion.latest().toString());
}
public boolean isConnected() {
return connection != null;
}
public void disconnect() throws BadServerResponse, XenAPIException, XmlRpcException {
Session.logout(connection);
// connection.dispose();
}
/**
* This is a Citrix-specific API, not implemented by vmware hosts ; trust
* agent will implement it when it's merged with provisioning agent from the
* asset tag branch
*
* @param tag
*/
public void setAssetTag(Sha1Digest tag) throws BadServerResponse, XenAPIException, XmlRpcException, NoSuchAlgorithmException, KeyManagementException {
if (!isConnected()) {
connect();
}
Set<Host> hostList = Host.getAll(connection);
Iterator iter = hostList.iterator();
// hasNext() will always be valid otherwise we will get an exception from the getAll method. So, we not need
// to throw an exception if the hasNext is false.
Host h = null;
if (iter.hasNext()) {
h = (Host) iter.next();
}
if (h == null) {
throw new IllegalStateException("Cannot find Citrix Xen host");
}
Map<String, String> myMap = new HashMap<>();
log.debug("sending the following to the xenserver: " + tag.toBase64());
myMap.put("tag", Base64.encodeBase64String(tag.toByteArray()));
//toByteArray()
String retval = h.callPlugin(connection, "tpm", "tpm_set_asset_tag", myMap);
log.debug("xenapi returned: {}", retval);
}
public HashMap<String, Pcr> getQuoteInformationForHost(String pcrList) {
log.debug("getQuoteInformationForHost pcrList == " + pcrList);
try {
// We cannot reuse the connections across different calls since they are tied to a particular host.
if (!isConnected()) {
connect();
}
String nonce = generateNonce();
String sessionId = generateSessionId();
String aikCertificate = getAIKCertificate();
// We do not need to connect again. So, commenting it out.
// System.err.println("stdalex-error connecting with " + userName + " " + password);
// Session.loginWithPassword(connection, userName, password, APIVersion.latest().toString());
// System.err.println( "CitrixClient: connected to server ["+hostIpAddress+"]");
Set<Host> hostList = Host.getAll(connection);
Iterator iter = hostList.iterator();
// hasNext() will always be valid otherwise we will get an exception from the getAll method. So, we not need
// to throw an exception if the hasNext is false.
File f, q, n;
Host h = null;
if (iter.hasNext()) {
h = (Host) iter.next();
}
if (h == null) {
throw new IllegalStateException("Cannot find Citrix Xen host");
}
/*
String aik = h.callPlugin(connection, "tpm", "tpm_get_attestation_identity", myMap);
int startP = aik.indexOf("<xentxt:TPM_Attestation_KEY_PEM>");
int endP = aik.indexOf("</xentxt:TPM_Attestation_KEY_PEM>");
// 32 is the size of the opening tag <xentxt:TPM_Attestation_KEY_PEM>
String cert = aik.substring(startP + "<xentxt:TPM_Attestation_KEY_PEM>".length(), endP);
log.debug("aikCert == " + cert);
keys key = new keys();
key.tpmAttKeyPEM = cert; // This is the actual value for AIK!!!!!
aikCertificate = key.tpmAttKeyPEM;
*/
log.debug("extracted aik cert from response: " + aikCertificate);
Map<String, String> myMap = new HashMap<>();
myMap.put("nonce", nonce);
long plugInCallStart = System.currentTimeMillis();
String quote = h.callPlugin(connection, "tpm", "tpm_get_quote", myMap);
long plugInCallStop = System.currentTimeMillis();
log.debug("Citrix PlugIn call: TPM quote retrieval time " + (plugInCallStop - plugInCallStart) + " milliseconds");
log.debug("extracted quote from response: " + quote);
//saveFile(getCertFileName(sessionId), Base64.decodeBase64(aikCertificate));
f = saveFile(getCertFileName(sessionId), aikCertificate.getBytes());
log.debug("saved certificate with session id: " + sessionId);
q = saveQuote(quote, sessionId);
log.debug("saved quote with session id: " + sessionId);
n = saveNonce(nonce, sessionId);
log.debug("saved nonce with session id: " + sessionId);
//createRSAKeyFile(sessionId);
log.debug("created RSA key file for session id: " + sessionId);
HashMap<String, Pcr> pcrMap = verifyQuoteAndGetPcr(sessionId, pcrList);
log.info("Got PCR map");
//log.log(Level.INFO, "PCR map = "+pcrMap); // need to untaint this first
f.delete();
q.delete();
n.delete();
return pcrMap;
} catch (ASException e) {
throw e;
// } catch(UnknownHostException e) {
// throw new ASException(e,ErrorCode.AS_HOST_COMMUNICATION_ERROR, hostIpAddress);
} catch (Exception e) {
log.debug("caught exception during login: " + e.toString() + " class: " + e.getClass());
throw new ASException(e, ErrorCode.AS_CITRIX_ERROR, e.toString());
}
}
public String generateNonce() {
try {
// Create a secure random number generator
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
// Get 1024 random bits
byte[] bytes = new byte[16];
sr.nextBytes(bytes);
// nonce = new BASE64Encoder().encode( bytes);
String nonce = Base64.encodeBase64String(bytes);
log.debug("Nonce Generated " + nonce);
return nonce;
} catch (NoSuchAlgorithmException e) {
throw new ASException(e);
}
}
private String generateSessionId() throws NoSuchAlgorithmException {
// Create a secure random number generator
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
// Get 1024 random bits
byte[] seed = new byte[1];
sr.nextBytes(seed);
sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
int nextInt = sr.nextInt();
String sessionId = "" + ((nextInt < 0) ? nextInt * -1 : nextInt);
log.debug("Session Id Generated [" + sessionId + "]");
return sessionId;
}
private String getNonceFileName(String sessionId) {
return "nonce_" + sessionId + ".data";
}
private String getQuoteFileName(String sessionId) {
return "quote_" + sessionId + ".data";
}
// Commenting the below function since it is not being used and klocwork is throwing a warning
/*private void saveCertificate(String aikCertificate, String sessionId) throws IOException {
if( aikCertificate.indexOf("-----BEGIN CERTIFICATE-----\n") < 0 && aikCertificate.indexOf("-----BEGIN CERTIFICATE-----") >= 0 ) {
log.debug( "adding newlines to certificate BEGIN tag");
aikCertificate = aikCertificate.replace("-----BEGIN CERTIFICATE-----", "-----BEGIN CERTIFICATE-----\n");
}
if( aikCertificate.indexOf("\n-----END CERTIFICATE-----") < 0 && aikCertificate.indexOf("-----END CERTIFICATE-----") >= 0 ) {
log.debug( "adding newlines to certificate END tag");
aikCertificate = aikCertificate.replace("-----END CERTIFICATE-----", "\n-----END CERTIFICATE-----");
}
saveFile(getCertFileName(sessionId), aikCertificate.getBytes());
}*/
private String getCertFileName(String sessionId) {
return "aikcert_" + sessionId + ".cer";
}
private File saveFile(String fileName, byte[] contents) throws IOException {
File file = new File(aikverifyhomeData + File.separator + fileName);
try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
log.debug(String.format("saving file %s to [%s]", fileName, aikverifyhomeData));
assert contents != null;
fileOutputStream.write(contents);
fileOutputStream.flush();
return file;
} catch (FileNotFoundException e) {
log.warn(String.format("cannot save to file %s in [%s]: %s", fileName, aikverifyhomeData, e.getMessage()));
throw e;
}
}
private File saveQuote(String quote, String sessionId) throws IOException {
// byte[] quoteBytes = new BASE64Decoder().decodeBuffer(quote);
byte[] quoteBytes = Base64.decodeBase64(quote);
File q = saveFile(getQuoteFileName(sessionId), quoteBytes);
return q;
}
private File saveNonce(String nonce, String sessionId) throws IOException {
// byte[] nonceBytes = new BASE64Decoder().decodeBuffer(nonce);
byte[] nonceBytes = Base64.decodeBase64(nonce);
File n = saveFile(getNonceFileName(sessionId), nonceBytes);
return n;
}
// Commenting the below function since it is not being used and klocwork is throwing a warning
/*private void createRSAKeyFile(String sessionId) {
String command = String.format("%s %s %s",opensslCmd,aikverifyhomeData + File.separator + getCertFileName(sessionId),aikverifyhomeData + File.separator+getRSAPubkeyFileName(sessionId));
log.debug( "RSA Key Command " + command);
CommandUtil.runCommand(command, false, "CreateRsaKey" );
//log.log(Level.INFO, "Result - {0} ", result);
} */
/*private String getRSAPubkeyFileName(String sessionId) {
return "rsapubkey_" + sessionId + ".key";
}*/
private HashMap<String, Pcr> verifyQuoteAndGetPcr(String sessionId, String pcrList) {
HashMap<String, Pcr> pcrMp = new HashMap<String, Pcr>();
log.debug("verifyQuoteAndGetPcr for session " + sessionId);
String command = String.format("%s -c %s %s %s", aikverifyCmd, aikverifyhomeData + File.separator + getNonceFileName(sessionId),
aikverifyhomeData + File.separator + getCertFileName(sessionId),
aikverifyhomeData + File.separator + getQuoteFileName(sessionId));
log.debug("Command: " + command);
List<String> result = CommandUtil.runCommand(command, true, "VerifyQuote");
// Sample output from command:
// 1 3a3f780f11a4b49969fcaa80cd6e3957c33b2275
// 17 bfc3ffd7940e9281a3ebfdfa4e0412869a3f55d8
//log.log(Level.INFO, "Result - {0} ", result); // need to untaint this first
// String pcrList = "0,1,2,3,17,18,19";
List<String> pcrs = Arrays.asList(pcrList.split(","));
//for(int i = 0; i < 25; i++) {
// if(pcrs.contains(String.valueOf(i)))
// System.out.println(i);
//}
for (String pcrString : result) {
String[] parts = pcrString.trim().split(" ");
if (parts.length == 2) {
String pcrNumber = parts[0].trim().replaceAll(pcrNumberUntaint, "").replaceAll("\n", "");
String pcrValue = parts[1].trim().replaceAll(pcrValueUntaint, "").replaceAll("\n", "");
boolean validPcrNumber = pcrNumberPattern.matcher(pcrNumber).matches();
boolean validPcrValue = pcrValuePattern.matcher(pcrValue).matches();
if (validPcrNumber && validPcrValue) {
log.debug("Result PCR " + pcrNumber + ": " + pcrValue);
if (pcrs.contains(pcrNumber)) {
pcrMp.put(pcrNumber, new Pcr(new PcrIndex(Integer.parseInt(pcrNumber)), new Sha1Digest(pcrValue)));
}
//PcrManifest(Integer.parseInt(pcrNumber),pcrValue));
}
} else {
log.info("Result PCR invalid");
}
/*
if(pcrs.contains(parts[0].trim()))
pcrMp.put(parts[0].trim(), new PcrManifest(Integer.parseInt(parts[0]),parts[1]));
*/
}
return pcrMp;
}
public HostInfo getHostInfo() throws NoSuchAlgorithmException, KeyManagementException, MalformedURLException, BadServerResponse, XenAPIException, XmlRpcException {
//log.info("stdalex-error getHostInfo IP:" + hostIpAddress + " port:" + port + " user: " + userName + " pw:" + password);
HostInfo response = new HostInfo();
if (!isConnected()) {
connect();
}
log.debug("CitrixClient: connected to server [" + hostIpAddress + "]");
// Map<String, String> myMap = new HashMap<String, String>();
Set<Host> hostList = Host.getAll(connection);
Iterator iter = hostList.iterator();
// hasNext() will always be valid otherwise we will get an exception from the getAll method. So, we not need
// to throw an exception if the hasNext is false.
Host h = null;
if (iter.hasNext()) {
h = (Host) iter.next();
}
if (h == null) {
throw new IllegalStateException("Cannot find Citrix Xen host");
}
response.setClientIp(hostIpAddress);
Map<String, String> map = h.getSoftwareVersion(connection);
response.setOsName(map.get("product_brand"));
response.setOsVersion(map.get("product_version"));
response.setVmmName("xen");
response.setVmmVersion(map.get("xen"));
map = h.getBiosStrings(connection);
response.setBiosOem(map.get("bios-vendor"));
response.setBiosVersion(map.get("bios-version"));
map = h.getCpuInfo(connection);
int stepping = Integer.parseInt(map.get("stepping"));
int model = Integer.parseInt(map.get("model"));
int family = Integer.parseInt(map.get("family"));
// EAX register contents is used for defining CPU ID and as well as family/model/stepping
// 0-3 bits : Stepping
// 4-7 bits: Model #
// 8-11 bits: Family code
// 12 & 13: Processor type, which will always be zero
// 14 & 15: Reserved
// 16 to 19: Extended model
// Below is the sample of the data got from the Citrix API
// Model: 45, Stepping:7 and Family: 6
// Mapping it to the EAX register we would get
// 0-3 bits: 7
// 4-7 bits: D (Actually 45 would be 2D. So, we would put D in 4-7 bits and 2 in 16-19 bits
// 8-11 bits: 6
//12-15 bits: 0
// 16-19 bits: 2
// 20-31 bits: Extended family and reserved, which will be 0
// So, the final content would be : 000206D7
// On reversing individual bytes, we would get D7 06 02 00
String modelInfo = Integer.toHexString(model);
String processorInfo = modelInfo.charAt(1) + Integer.toHexString(stepping) + " " + "0" + Integer.toHexString(family) + " " + "0" + modelInfo.charAt(0);
processorInfo = processorInfo.trim().toUpperCase();
response.setProcessorInfo(processorInfo);
java.util.Date date = new java.util.Date();
response.setTimeStamp(new Timestamp(date.getTime()).toString());
// log.trace("stdalex-error leaving getHostInfo");
return response;
}
public String getSystemUUID() throws NoSuchAlgorithmException, KeyManagementException, XenAPIException, BadServerResponse, XmlRpcException {
if (!isConnected()) {
connect();
}
log.debug("CitrixClient getSystemUUID: connected to server [" + hostIpAddress + "]");
Map<String, String> myMap = new HashMap<String, String>();
Set<Host> hostList = Host.getAll(connection);
Iterator iter = hostList.iterator();
// hasNext() will always be valid otherwise we will get an exception from the getAll method. So, we not need
// to throw an exception if the hasNext is false.
Host h = null;
if (iter.hasNext()) {
h = (Host) iter.next();
}
if (h == null) {
throw new IllegalStateException("Cannot find Citrix Xen host");
}
String aik = h.callPlugin(connection, "tpm", "tpm_get_attestation_identity", myMap);
int startP = aik.indexOf("<xentxt:System_UUID>");
int endP = aik.indexOf("</xentxt:System_UUID>");
// 32 is the size of the opening tag <xentxt:TPM_Attestation_KEY_PEM>
String systemUUID = aik.substring(startP + "<xentxt:System_UUID>".length(), endP);
log.debug("systemUUID == " + systemUUID);
String resp = systemUUID.toLowerCase();
// log.trace("stdalex-error getAIKCert: returning back: " + resp);
return resp;
}
public String getAIKCertificate() throws NoSuchAlgorithmException, KeyManagementException, BadServerResponse, XenAPIException, XmlRpcException {
// log.info("stdalex-error getAIKCert IP:" + hostIpAddress + " port:" + port + " user: " + userName + " pw:" + password); // removed to prevent leaking secrets
//log.debug("CitrixClient: AIKCert: " + AIKCert);
long startTime = System.currentTimeMillis();
if (AIKCert != null) {
log.debug("CitrixClient: AIKCert already generated: " + AIKCert);
return AIKCert;
} else {
if (!isConnected()) {
connect();
}
log.debug("CitrixClient: generating AIKCert");
Map<String, String> myMap = new HashMap<String, String>();
Set<Host> hostList = Host.getAll(connection);
Iterator iter = hostList.iterator();
// hasNext() will always be valid otherwise we will get an exception from the getAll method. So, we not need
// to throw an exception if the hasNext is false.
Host h = null;
if (iter.hasNext()) {
h = (Host) iter.next();
}
if (h == null) {
throw new IllegalStateException("Cannot find Citrix Xen host");
}
log.debug("TIMETAKEN: get host list: {}", System.currentTimeMillis() - startTime);
startTime = System.currentTimeMillis();
String aik = h.callPlugin(connection, "tpm", "tpm_get_attestation_identity", myMap);
log.debug("TIMETAKEN: citrix api: {}", System.currentTimeMillis() - startTime);
int startP = aik.indexOf("<xentxt:TPM_Attestation_KEY_PEM>");
int endP = aik.indexOf("</xentxt:TPM_Attestation_KEY_PEM>");
// 32 is the size of the opening tag <xentxt:TPM_Attestation_KEY_PEM>
String cert = aik.substring(startP + "<xentxt:TPM_Attestation_KEY_PEM>".length(), endP);
log.debug("aikCert == " + cert);
keys key = new keys();
key.tpmAttKeyPEM = cert; // This is the actual value for AIK!!!!!
//resp = new String( Base64.decodeBase64(key.tpmAttKeyPEM));
String resp = key.tpmAttKeyPEM;//new String(key.tpmAttKeyPEM);
// log.trace("stdalex-error getAIKCert: returning back: " + resp);
AIKCert = resp;
return AIKCert;
}
}
}