/* * Copyright (C) 2014 Intel Corporation * All rights reserved. */ package com.intel.mtwilson.privacyca.v2.rpc; import com.intel.dcsg.cpg.x509.X509Util; import com.intel.mtwilson.My; import com.intel.mtwilson.launcher.ws.ext.RPC; import gov.niarl.his.privacyca.TpmIdentityProof; import gov.niarl.his.privacyca.TpmIdentityRequest; import gov.niarl.his.privacyca.TpmKeyParams; import gov.niarl.his.privacyca.TpmPubKey; import gov.niarl.his.privacyca.TpmSymmetricKey; import gov.niarl.his.privacyca.TpmUtils; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.util.concurrent.Callable; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import org.apache.commons.io.IOUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; /** * * @author jbuhacoff */ @RPC("aik_request_submit_response") public class IdentityRequestSubmitResponse implements Callable<byte[]> { private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(IdentityRequestSubmitResponse.class); private byte[] identityRequestResponseToChallenge; public void setChallengeResponse(byte[] identityRequestResponseToChallenge) { this.identityRequestResponseToChallenge = identityRequestResponseToChallenge; } public byte[] getChallengeResponse() { return identityRequestResponseToChallenge; } @Override @RequiresPermissions("host_aiks:certify") public byte[] call() throws Exception { RSAPrivateKey caPrivKey = TpmUtils.privKeyFromP12(My.configuration().getPrivacyCaIdentityP12().getAbsolutePath(), My.configuration().getPrivacyCaIdentityPassword()); X509Certificate caPubCert = TpmUtils.certFromP12(My.configuration().getPrivacyCaIdentityP12().getAbsolutePath(), My.configuration().getPrivacyCaIdentityPassword()); int validityDays = My.configuration().getPrivacyCaIdentityValidityDays(); //decrypt response TpmIdentityRequest returnedIR = new TpmIdentityRequest(identityRequestResponseToChallenge); byte[] decryptedIdentityRequestChallenge = returnedIR.decryptRaw(caPrivKey); // should be the same 32 bytes that we sent as the encrypted challenge TpmIdentityProof idProof; X509Certificate ekCert; // find the existing challenge and idproof // save the challenge and idproof for use in identity request submit response if the client successfully answers the challenge // the filename is the challenge (in hex) and the content is the idproof File datadir = new File(My.filesystem().getBootstrapFilesystem().getVarPath() + File.separator + "privacyca-aik-requests"); if( !datadir.exists() ) { datadir.mkdirs(); } String filename = TpmUtils.byteArrayToHexString(decryptedIdentityRequestChallenge); //Hex.encodeHexString(identityRequestChallenge) log.debug("Filename: {}", filename); File challengeFile = datadir.toPath().resolve(filename).toFile(); if( !challengeFile.exists() ) { throw new RuntimeException("Invalid challenge response"); } try(FileInputStream in = new FileInputStream(challengeFile)) { byte[] idProofBytes = IOUtils.toByteArray(in); String optionsFilename = filename + ".opt"; try(FileInputStream optionsIn = new FileInputStream(datadir.toPath().resolve(optionsFilename).toFile())) { String hexOptions = IOUtils.toString(optionsIn); Util.TpmIdentityProofOptions options = Util.decodeTpmIdentityProofOptionsFromHex(hexOptions); idProof = new TpmIdentityProof(idProofBytes, options.TrousersModeIV, options.TrousersModeSymkeyEncscheme, options.TrousersModeBlankOeap); } } String ekcertFilename = filename + ".ekcert"; File ekcertFile = datadir.toPath().resolve(ekcertFilename).toFile(); try(FileInputStream in = new FileInputStream(ekcertFile)) { byte[] ekcertBytes = IOUtils.toByteArray(in); ekCert = X509Util.decodeDerCertificate(ekcertBytes); } //compare decrypted response to challenge //if match, create AIC; else create failure code byte[] certBytes = TpmUtils.makeCert(idProof, caPrivKey, caPubCert, validityDays, 0).getEncoded(); //encrypt response and return return createReturn(idProof.getAik(), (RSAPublicKey)ekCert.getPublicKey(), certBytes); } private static byte[] createReturn(TpmPubKey aik, RSAPublicKey pubEk, byte[] challengeRaw) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, TpmUtils.TpmUnsignedConversionException, IOException{ byte [] key = TpmUtils.createRandomBytes(16); byte [] iv = TpmUtils.createRandomBytes(16); byte [] encryptedBlob = TpmUtils.concat(iv, TpmUtils.TCGSymEncrypt(challengeRaw, key, iv)); byte [] credSize = TpmUtils.intToByteArray(encryptedBlob.length); TpmSymmetricKey symKey = new TpmSymmetricKey(); symKey.setKeyBlob(key); symKey.setAlgorithmId(TpmKeyParams.TPM_ALG_AES); symKey.setEncScheme(TpmKeyParams.TPM_ES_SYM_CBC_PKCS5PAD); TpmKeyParams keyParms = new TpmKeyParams(); keyParms.setAlgorithmId(TpmKeyParams.TPM_ALG_AES); keyParms.setEncScheme(TpmKeyParams.TPM_ES_NONE); keyParms.setSigScheme((short)0); keyParms.setSubParams(null); keyParms.setTrouSerSmode(true); byte [] asymBlob = TpmUtils.TCGAsymEncrypt(TpmUtils.concat(symKey.toByteArray(), TpmUtils.sha1hash(aik.toByteArray())), pubEk); byte [] symBlob = TpmUtils.concat(TpmUtils.concat(credSize, keyParms.toByteArray()), encryptedBlob); return TpmUtils.concat(asymBlob, symBlob); } }