499 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Xml;
using Intel.Management.Wsman;
namespace Intel.Management.PSModule.Heci
{
public enum CertChainStatus
{
NotStarted = 0,
InProgress = 1,
Complete = 2,
}
public enum HashAlgorithmType
{
Unknown =0,
Sha1=1,
Sha256=2,
Sha384=3,
}
public class AmtSetupRecord
{
IManagedInstance _recordObj;
public AmtSetupRecord(IManagedInstance recordObj)
{
_recordObj = recordObj;
}
public DateTime Timestamp
{
get
{
return Amt.AmtDriveInfo.FormatDate(
_recordObj.GetProperty("CreationTimeStamp"));
}
}
public string LogName
{
get
{
return _recordObj.GetProperty("LogName").ToString();
}
}
public string RecordID
{
get
{
return _recordObj.GetProperty("RecordID").ToString();
}
}
public bool SecureDNS
{
get
{
if (_recordObj.GetProperty("SecureDNS").IsNull)
return false;
return bool.Parse(_recordObj.GetProperty("SecureDNS").ToString());
}
}
public string CertificateCN
{
get
{
if (_recordObj.GetProperty("CertificateCN").IsNull)
return string.Empty;
return
_recordObj.GetProperty("CertificateCN").ToString();
}
}
public HashAlgorithmType HashAlgorithm
{
get
{
if (!_recordObj.GetProperty("HashAlgorithm").IsNull)
{
return (HashAlgorithmType)int.Parse(_recordObj.GetProperty("HashAlgorithm").ToString());
}
else if (!_recordObj.GetProperty("SelectedHashType").IsNull)
{
return (HashAlgorithmType)int.Parse(_recordObj.GetProperty("SelectedHashType").ToString());
}
return HashAlgorithmType.Unknown;
}
}
public string CertificateHash
{
get
{
if (!_recordObj.GetProperty("ProvCertificateHash").IsNull)
{
return _recordObj.GetProperty("ProvCertificateHash").ToString();
}
else if (!_recordObj.GetProperty("SelectedHashData").IsNull)
{
return _recordObj.GetProperty("SelectedHashData").ToString();
}
return string.Empty;
}
}
public string[] CaCertificateSerials
{
get
{
List<string> result = new List<string>();
foreach (IWsmanItem item in _recordObj.GetProperty("CaCertificateSerials"))
{
result.Add(item.ToString());
}
return result.ToArray();
}
}
public bool AdditionalCaSerialNums
{
get
{
if (_recordObj.GetProperty("AdditionalCaSerialNums").IsNull)
return false;
return bool.Parse(_recordObj.GetProperty("AdditionalCaSerialNums").ToString());
}
}
public bool HashIsOemDefault
{
get
{
if (_recordObj.GetProperty("HashIsOemDefault").IsNull)
return false;
return bool.Parse(_recordObj.GetProperty("HashIsOemDefault").ToString());
}
}
}
public class AmtSetupParameters
{
CertChainStatus _status;
X509Certificate2Collection _chain;
byte[] _mcNonce;
byte[] _configNonce;
byte[] _signature;
string _passwordHash;
IWsmanConnection _conn;
public AmtSetupParameters()
{
_status = CertChainStatus.NotStarted;
_chain = new X509Certificate2Collection();
}
public AmtSetupParameters(IWsmanConnection conn, CertChainStatus status)
{
_status = status;
_conn = conn;
_chain = new X509Certificate2Collection();
}
public override string ToString()
{
return string.Empty;
}
public void Reset()
{
_mcNonce = null;
_signature = null;
_passwordHash = null;
}
public CertChainStatus CertChainStatus
{
get { return _status; }
}
public string PasswordHash
{
get
{
return _passwordHash;
}
set
{
_passwordHash = null;
}
}
public void SetPassword(string password)
{
// get the realm from the connection
if (_conn == null)
throw new InvalidOperationException("Connection object not set");
IManagedInstance settingsObj = _conn.NewInstance("SELECT * FROM AMT_GeneralSettings");
string realm = settingsObj.GetProperty("DigestRealm").ToString();
SetPassword("admin", password, realm);
}
public void SetPassword(string admin, string password, string realm)
{
MD5 md5 = new MD5CryptoServiceProvider();
md5.Initialize();
StringBuilder builder = new StringBuilder();
builder.Append(admin);
builder.Append(":");
builder.Append(realm);
builder.Append(":");
builder.Append(password);
_passwordHash = BitConverter.ToString(md5.ComputeHash(Encoding.ASCII.GetBytes(builder.ToString())));
_passwordHash = _passwordHash.Replace("-", string.Empty);
}
X509Certificate2 FindIssuer(X509Certificate2 childCert)
{
//if the root is passed in return null
if (childCert.Subject.Equals(childCert.Issuer))
return null;
foreach (X509Certificate2 cert in _chain)
{
if (cert.Subject.Equals(childCert.Issuer))
return cert;
}
return null;
}
public void SaveChain()
{
// get the realm from the connection
if (_conn == null)
throw new InvalidOperationException("Connection object not set");
IManagedReference refToService = _conn.NewReference("IPS_HostBasedSetupService");
refToService.AddSelector("Name", "Intel(r) AMT Host Based Setup Service");
IManagedInstance serviceObj = null;
//X509Certificate2Collection certs = new X509Certificate2Collection();
//certs.Import("C:\\Users\\amtadmin\\Documents\\Dev\\HBP\\setupchain.p7b");
List<string> issuers = new List<string>();
// loop throug the certs and find the root
foreach (X509Certificate2 cert in _chain)
{
issuers.Add(cert.Issuer);
}
List<X509Certificate2> certs = new List<X509Certificate2>();
X509Certificate2 nextCert = null;
// find leaf (is not an issuer of any cert)
foreach (X509Certificate2 cert in certs)
{
if (issuers.IndexOf(cert.Subject) < 0)
nextCert = cert;
}
while(nextCert !=null)
{
certs.Add(nextCert);
nextCert = FindIssuer(nextCert);
}
foreach (X509Certificate2 cert in certs)
{
while (_status!=CertChainStatus.Complete)
{
bool isLeaf = cert.Equals(certs.First());
bool isRoot = cert.Equals(certs.Last());
IManagedInstance inputObj = refToService.CreateMethodInput("AddNextCertInChain");
inputObj.SetProperty("NextCertificate", Convert.ToBase64String(cert.RawData));
inputObj.SetProperty("IsLeafCertificate", isLeaf.ToString().ToLower());
inputObj.SetProperty("IsRootCertificate", isRoot.ToString().ToLower());
IManagedInstance outObj = refToService.InvokeMethod(inputObj);
switch (outObj.GetProperty("ReturnValue").ToString())
{
case "0":
break;
case "1":
throw new ApplicationException("Invalid Parameter");
case "2":
throw new ApplicationException("Internal Error");
case "3":
throw new ApplicationException("Invalid State");
case "4":
throw new ApplicationException("Invalid certificate");
case "5":
//Chain length exceeded
throw new ApplicationException("chain length exceeded");
}
serviceObj = refToService.Get(); // refresh the service Object
_status=(CertChainStatus)int.Parse(serviceObj.GetProperty("CertChainStatus").ToString());
}
}
}
public byte[] ConfiguationNonce
{
get
{
return _configNonce;
}
set
{
_configNonce = value;
}
}
public byte[] McNonce
{
get
{
return _mcNonce;
}
set
{
_mcNonce = value;
}
}
public byte[] Signature
{
get
{
return _signature;
}
}
public string SignatureDescription
{
get { return "SHA256"; }
}
public byte[] Data
{
get
{
if (_configNonce == null)
throw new InvalidOperationException("No Configuration Nonce has been set");
if (_mcNonce == null)
throw new InvalidOperationException("No Mc Nonce has been set");
byte[] data = new byte[_configNonce.Length + _mcNonce.Length];
Array.Copy(_configNonce, 0, data, 0, _configNonce.Length);
Array.Copy(_mcNonce, 0, data, _configNonce.Length, _mcNonce.Length);
return data;
}
}
public void Import(string path)
{
_chain.Import(path);
}
public void ImportKey(string path, string password)
{
_chain.Import(path, password, X509KeyStorageFlags.Exportable);
}
string ToXmlString()
{
if (_mcNonce == null)
GenerateMcNonce();
StringBuilder builder = new StringBuilder();
builder.Append("<AmtSetupParameters>");
builder.Append("<McNonce>");
builder.Append(Convert.ToBase64String(_mcNonce));
builder.Append("</McNonce>");
builder.Append("<ConfigNonce>");
builder.Append(Convert.ToBase64String(_configNonce));
builder.Append("</ConfigNonce>");
builder.Append("</AmtSetupParameters>");
return builder.ToString();
}
public void FromXmlString(string xmlString)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlString);
}
public void GenerateMcNonce()
{
if (_mcNonce == null)
_mcNonce = new byte[20];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(_mcNonce);
}
public void SignData()
{
if (_mcNonce == null)
GenerateMcNonce();
SignData(Data);
}
public void SignData(byte[] data)
{
RSACryptoServiceProvider rsa=null;
//find the public key in the collection
foreach (X509Certificate2 cert in _chain)
{
if (cert.HasPrivateKey)
rsa = cert.PrivateKey as RSACryptoServiceProvider;
}
if (rsa == null)
throw new DriveException("Private key not found in certifcate chain");
RSAParameters rp = rsa.ExportParameters(true);
rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rp);
_signature = rsa.SignData(data, SignatureDescription);
if (!rsa.VerifyData(data, SignatureDescription, _signature))
{
throw new DriveException("RSA Signature not valid");
}
}
public X509Certificate2Collection Chain
{
get
{
return _chain;
}
set
{
_chain = value;
}
}
}
}