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 result = new List(); 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 issuers = new List(); // loop throug the certs and find the root foreach (X509Certificate2 cert in _chain) { issuers.Add(cert.Issuer); } List certs = new List(); 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(""); builder.Append(""); builder.Append(Convert.ToBase64String(_mcNonce)); builder.Append(""); builder.Append(""); builder.Append(Convert.ToBase64String(_configNonce)); builder.Append(""); builder.Append(""); 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; } } } }