internal static bool ExtractHubTwinAndVerify(TwinCollection twinDesiredProperties) { try { // Extract Desired properties JObject desiredProperties = new JObject(); JObject twinJobject = JObject.Parse(twinDesiredProperties.ToString()); desiredProperties["routes"] = twinJobject["routes"]; desiredProperties["schemaVersion"] = twinJobject["schemaVersion"]; desiredProperties["storeAndForwardConfiguration"] = twinJobject["storeAndForwardConfiguration"]; // Extract Integrity section JToken integrity = twinJobject["integrity"]; JToken header = integrity["header"]; JToken signerCertJtoken = integrity["header"]["signercert"]; string combinedCert = signerCertJtoken.Aggregate(string.Empty, (res, next) => res + next); X509Certificate2 signerCert = new X509Certificate2(Convert.FromBase64String(combinedCert)); JToken signature = integrity["signature"]["bytes"]; // Extract Signature and algorithm byte[] signatureBytes = Convert.FromBase64String(signature.ToString()); JToken algo = integrity["signature"]["algorithm"]; KeyValuePair <string, HashAlgorithmName> algoResult = SignatureValidator.ParseAlgorithm(algo.ToString()); Events.ExtractHubTwinSucceeded(); return(SignatureValidator.VerifySignature(desiredProperties.ToString(), header.ToString(), signatureBytes, signerCert, algoResult.Key, algoResult.Value)); } catch (Exception ex) { Events.ExtractHubTwinAndVerifyFailed(ex); throw ex; } }
public static void ParseAlgorithmTest(string algorithm, bool hasParseExcpetion, string expectedAlgoScheme, HashAlgorithmName expectedHashAlgo) { if (!hasParseExcpetion) { KeyValuePair <string, HashAlgorithmName> actualResult = SignatureValidator.ParseAlgorithm(algorithm); KeyValuePair <string, HashAlgorithmName> expectedResult = new KeyValuePair <string, HashAlgorithmName>(expectedAlgoScheme, expectedHashAlgo); Assert.Equal(actualResult, expectedResult); } else { Assert.Throws <TwinSignatureAlgorithmException>(() => SignatureValidator.ParseAlgorithm(algorithm)); } }
internal bool ExtractHubTwinAndVerify(TwinCollection twinDesiredProperties) { try { // Extract Desired properties JObject desiredProperties = new JObject(); JObject twinJobject = JObject.Parse(twinDesiredProperties.ToString()); desiredProperties["routes"] = twinJobject["routes"]; desiredProperties["schemaVersion"] = twinJobject["schemaVersion"]; desiredProperties["storeAndForwardConfiguration"] = twinJobject["storeAndForwardConfiguration"]; if (desiredProperties["mqttBroker"] != null) { desiredProperties["mqttBroker"] = twinJobject["mqttBroker"]; } // Check if Manifest Trust Bundle is configured X509Certificate2 manifestTrustBundleRootCertificate; if (!this.manifestTrustBundle.HasValue && twinJobject["integrity"] == null) { // Actual code path would never get here as we check enablement before this. Added for Unit test purpose only. Events.ManifestSigningIsNotEnabled(); throw new ManifestSigningIsNotEnabledProperly("Manifest Signing is Disabled."); } else if (!this.manifestTrustBundle.HasValue && twinJobject["integrity"] != null) { Events.ManifestTrustBundleIsNotConfigured(); throw new ManifestSigningIsNotEnabledProperly("Deployment manifest is signed but the Manifest Trust bundle is not configured. Please configure in config.toml"); } else if (this.manifestTrustBundle.HasValue && twinJobject["integrity"] == null) { Events.DeploymentManifestIsNotSigned(); throw new ManifestSigningIsNotEnabledProperly("Manifest Trust bundle is configured but the Deployment manifest is not signed. Please sign it."); } else { // deployment manifest is signed and also the manifest trust bundle is configured manifestTrustBundleRootCertificate = this.manifestTrustBundle.OrDefault(); } // Extract Integrity header section JToken integrity = twinJobject["integrity"]; JToken header = integrity["header"]; // Extract Signer Cert section JToken signerCertJtoken = integrity["header"]["signercert"]; string signerCombinedCert = signerCertJtoken.Aggregate(string.Empty, (res, next) => res + next); X509Certificate2 signerCert = new X509Certificate2(Convert.FromBase64String(signerCombinedCert)); // Extract Intermediate CA Cert section JToken intermediatecacertJtoken = integrity["header"]["intermediatecacert"]; string intermediatecacertCombinedCert = signerCertJtoken.Aggregate(string.Empty, (res, next) => res + next); X509Certificate2 intermediatecacert = new X509Certificate2(Convert.FromBase64String(intermediatecacertCombinedCert)); // Extract Signature bytes and algorithm section JToken signature = integrity["signature"]["bytes"]; byte[] signatureBytes = Convert.FromBase64String(signature.ToString()); JToken algo = integrity["signature"]["algorithm"]; string algoStr = algo.ToString(); KeyValuePair <string, HashAlgorithmName> algoResult = SignatureValidator.ParseAlgorithm(algoStr); // Extract the manifest trust bundle certificate and verify chaining bool signatureVerified = false; using (IDisposable verificationTimer = Metrics.StartTwinSignatureTimer()) { // Currently not verifying the chaining as Manifest signer client already does that. // There is known bug in which the certs are not processed correctly which breaks the chaining verification. signatureVerified = SignatureValidator.VerifySignature(desiredProperties.ToString(), header.ToString(), signatureBytes, signerCert, algoResult.Key, algoResult.Value); } Metrics.ReportTwinSignatureResult(signatureVerified, algoStr); if (signatureVerified) { Events.ExtractHubTwinSucceeded(); } return(signatureVerified); } catch (Exception ex) { Metrics.ReportTwinSignatureResult(false); Events.ExtractHubTwinAndVerifyFailed(ex); throw ex; } }
internal bool ExtractHubTwinAndVerify(TwinCollection twinDesiredProperties) { try { // Extract Desired properties JObject desiredProperties = new JObject(); JObject twinJobject = JObject.Parse(twinDesiredProperties.ToString()); desiredProperties["routes"] = twinJobject["routes"]; desiredProperties["schemaVersion"] = twinJobject["schemaVersion"]; desiredProperties["storeAndForwardConfiguration"] = twinJobject["storeAndForwardConfiguration"]; if (desiredProperties["mqttBroker"] != null) { desiredProperties["mqttBroker"] = twinJobject["mqttBroker"]; } // Check if Manifest Trust Bundle is configured X509Certificate2 manifestTrustBundleRootCertificate; if (!this.manifestTrustBundle.HasValue && twinJobject["integrity"] == null) { // Actual code path would never get here as we check enablement before this. Added for Unit test purpose only. Events.ManifestSigningIsNotEnabled(); throw new ManifestSigningIsNotEnabledProperly("Manifest Signing is Disabled."); } else if (!this.manifestTrustBundle.HasValue && twinJobject["integrity"] != null) { Events.ManifestTrustBundleIsNotConfigured(); throw new ManifestSigningIsNotEnabledProperly("Deployment manifest is signed but the Manifest Trust bundle is not configured. Please configure in config.toml"); } else if (this.manifestTrustBundle.HasValue && twinJobject["integrity"] == null) { Events.DeploymentManifestIsNotSigned(); throw new ManifestSigningIsNotEnabledProperly("Manifest Trust bundle is configured but the Deployment manifest is not signed. Please sign it."); } else { // deployment manifest is signed and also the manifest trust bundle is configured manifestTrustBundleRootCertificate = this.manifestTrustBundle.OrDefault(); } // Extract Integrity header section JToken integrity = twinJobject["integrity"]; JToken header = integrity["header"]; // Extract Signer Cert section JToken signerCertJtoken = integrity["header"]["signercert"]; string signerCombinedCert = signerCertJtoken.Aggregate(string.Empty, (res, next) => res + next); X509Certificate2 signerCert = new X509Certificate2(Convert.FromBase64String(signerCombinedCert)); // Extract Intermediate CA Cert section JToken intermediatecacertJtoken = integrity["header"]["intermediatecacert"]; string intermediatecacertCombinedCert = signerCertJtoken.Aggregate(string.Empty, (res, next) => res + next); X509Certificate2 intermediatecacert = new X509Certificate2(Convert.FromBase64String(intermediatecacertCombinedCert)); // Extract the manifest trust bundle certificate and verify chaining if (!CertificateHelper.VerifyManifestTrustBunldeCertificateChaining(signerCert, intermediatecacert, manifestTrustBundleRootCertificate)) { throw new ManifestTrustBundleChainingFailedException("The signer cert with or without the intermediate CA cert in the twin does not chain up to the Manifest Trust Bundle Root CA configured in the device"); } // Extract Signature bytes and algorithm section JToken signature = integrity["signature"]["bytes"]; byte[] signatureBytes = Convert.FromBase64String(signature.ToString()); JToken algo = integrity["signature"]["algorithm"]; KeyValuePair <string, HashAlgorithmName> algoResult = SignatureValidator.ParseAlgorithm(algo.ToString()); Events.ExtractHubTwinSucceeded(); return(SignatureValidator.VerifySignature(desiredProperties.ToString(), header.ToString(), signatureBytes, signerCert, algoResult.Key, algoResult.Value)); } catch (Exception ex) { Events.ExtractHubTwinAndVerifyFailed(ex); throw ex; } }
static void Main() { // Initialize & Check if the given signer cert is issued by root CA try { // Check launch settings and display it CheckInputAndDisplayLaunchSettings(); // Verify certificate chaining if (!VerifyCertificate()) { throw new Exception("Please provide a signer cert issued by the given root CA"); } } catch (Exception e) { Console.WriteLine(e.ToString()); Environment.Exit(0); } // Read the deployment manifest file and get signature of each modules's desired properties try { var manifestFileHandle = File.OpenText(DeploymentManifestFilePath); var deploymentManifestContentJson = JObject.Parse(manifestFileHandle.ReadToEnd()); if (deploymentManifestContentJson["modulesContent"] != null) { // Get the DSA and SHA algorithm KeyValuePair <string, HashAlgorithmName> algoResult = SignatureValidator.ParseAlgorithm(DsaAlgorithm.ToString()); // Read the signer certificate and manifest version number and create integrity header object var header = GetIntegrityHeader(SignerCertPath); // Read each module's content and its desired properties var modulesContentJson = deploymentManifestContentJson["modulesContent"]; JObject modulesContentJobject = JObject.Parse(modulesContentJson.ToString()); foreach (JProperty property in modulesContentJobject.Properties()) { if (modulesContentJson[property.Name] != null) { if (modulesContentJson[property.Name]["properties.desired"] != null) { var modulesDesired = modulesContentJson[property.Name]["properties.desired"]; var moduleName = property.Name.ToString(); if (moduleName != "$edgeAgent" && moduleName != "$edgeHub") { Console.WriteLine($"Do you want to sign the desired properties of the module - {moduleName}? - Type Y or N to continue"); Console.WriteLine("!!! Important Note !!! - If the module's desired properties are signed then the module's application code has to be rewritten to verify signatures"); string userSigningChoice = Console.ReadLine(); if (userSigningChoice != "Y" && userSigningChoice != "y") { Console.WriteLine($"{moduleName} will not be signed"); continue; } } Console.WriteLine($"Signing Module: {property.Name}"); object signature = new { bytes = CertificateUtil.GetJsonSignature(algoResult.Key, algoResult.Value, modulesDesired.ToString(), header, SignerPrivateKeyPath), algorithm = DsaAlgorithm }; deploymentManifestContentJson["modulesContent"][property.Name]["properties.desired"]["integrity"] = JObject.FromObject(new { header, signature }); } else { throw new Exception($"Could not find {property.Name}'s desired properties in the manifest file"); } } else { throw new Exception($"Could not find {property.Name} in the manifest file"); } } using var signedDeploymentfile = File.CreateText(SignedDeploymentManifestFilePath); signedDeploymentfile.Write(deploymentManifestContentJson); } else { throw new Exception("Could not find modulesContent in the manifest file"); } } catch (Exception e) { Console.WriteLine(e.ToString()); Environment.Exit(0); } }