void QueryFWStatus() { try { var twin = Me.GetTwinAsync().Result; var myFwid = Helpers.Hexify(Helpers.HashData(new byte[] { (byte)CurrentFwVersionNumber }, 0, 1)); var targetFwVersionNumber = twin.Properties.Desired["VersionNumber"]; Int64 currentReportedVersionNumber = -1; if (twin.Properties.Reported.Contains("VersionNumber")) { currentReportedVersionNumber = (Int64)twin.Properties?.Reported["VersionNumber"]; } // update our version number if hub version number is not current if (currentReportedVersionNumber < 0 || CurrentFwVersionNumber != currentReportedVersionNumber || updateCurrentVersionNumber ) { TwinCollection t = new TwinCollection(); t["VersionNumber"] = CurrentFwVersionNumber; Me.UpdateReportedPropertiesAsync(t).Wait(); updateCurrentVersionNumber = false; } // if the target version number is not current, then flag that we need a FW update if (targetFwVersionNumber != CurrentFwVersionNumber.ToString()) { FirmwareUpdateNeeded = true; DesiredFwVersionNumber = targetFwVersionNumber; Debug.WriteLine("Need to update myself"); } else { FirmwareUpdateNeeded = false; Debug.WriteLine("Firmware version is good"); } // am I p0wned? If I'm P0wned I won't update myself if (twin.Properties.Desired.Contains("POwned")) { P0wned = (bool)twin.Properties?.Desired["POwned"]; } } catch (Exception e) { Debug.WriteLine("Error querying status" + e.ToString()); throw; } return; }
internal static bool ValidateBareCertificateWithBcrypt(X509Certificate2 certificate) { var deviceInfo = ExtensionDecoder.Decode(certificate); // check we have a good extension if (deviceInfo == null) { Helpers.Notify("Certificate does not have well-formed RIoT extension", true); return(false); } var devIdPubKeyDEREncoded = deviceInfo.EncodedDeviceIDKey; if (devIdPubKeyDEREncoded.Length != 65) { Helpers.Notify("Public key in extension has incorrect length", true); return(false); } // We need to convert to the Windows key format before we can import // #define BCRYPT_ECDSA_PUBLIC_P256_MAGIC 0x31534345 // ECS1 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa375520(v=vs.85).aspx byte[] windowsEncodedKey = new byte[32 * 2 + 4 + 4]; // todo - endianess byte[] magic = BitConverter.GetBytes((uint)0x31534345); byte[] len = BitConverter.GetBytes((uint)32); Array.Copy(magic, 0, windowsEncodedKey, 0, 4); Array.Copy(len, 0, windowsEncodedKey, 4, 4); Array.Copy(devIdPubKeyDEREncoded, 1, windowsEncodedKey, 8, 32); Array.Copy(devIdPubKeyDEREncoded, 32 + 1, windowsEncodedKey, 8 + 32, 32); var devIdPubKey = CngKey.Import(windowsEncodedKey, CngKeyBlobFormat.EccPublicBlob); ECDsaCng verifier = new ECDsaCng(devIdPubKey); ECDsaCng testSigner = new ECDsaCng(256); var sig = testSigner.SignData(new byte[] { 1, 2, 3, 4 }); bool okx = testSigner.VerifyData(new byte[] { 1, 2, 3, 4 }, sig); var bits = ExtensionDecoder.Decompose(certificate); var tbsHash = Helpers.HashData(bits.Tbs, 0, bits.Tbs.Length); bool ok = verifier.VerifyHash(tbsHash, bits.Signature); return(true); }
internal void MakeCertChain(DeviceBundle bundle, int chainLen, int fwidSeed) { var aliasCert = bundle.AliasCert; DateTime now = DateTime.Now; byte[] fwid = Helpers.HashData(new byte[1] { 0 }, 0, 1); const int keyStrength = 256; CryptoApiRandomGenerator rg = new CryptoApiRandomGenerator(); SecureRandom random = new SecureRandom(rg); KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, keyStrength); var keyPairGenerator = new ECKeyPairGenerator(); keyPairGenerator.Init(keyGenerationParameters); // Starting the loop we have a (not yet certified) DeviceID public key // and the Issuer of the Alias Cert (which we want to be the DevID-cert DN.) List <X509Certificate> certChain = new List <X509Certificate>(); var lastCertIssuer = aliasCert.IssuerDN; var lastPubKey = bundle.DeviceIDPublic;; AsymmetricCipherKeyPair lastKeyPair = null; for (int j = 0; j < chainLen; j++) { bool rootCert = j == chainLen - 1; bool lastButOne = j == chainLen - 2; AsymmetricCipherKeyPair caKey = keyPairGenerator.GenerateKeyPair(); X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); certGen.SetSerialNumber(new BigInteger(new byte[] { 1, 2, 3, 4, 5 })); var issuerDn = lastButOne ? new X509Name($"CN=Vendor Root CA O=MSR_TEST, C=US") : new X509Name($"CN=Vendor Intermediate CA {j}, O=MSR_TEST, C=US"); if (rootCert) { issuerDn = lastCertIssuer; } certGen.SetIssuerDN(issuerDn); certGen.SetSubjectDN(lastCertIssuer); certGen.SetNotBefore(now); certGen.SetNotAfter(now + new TimeSpan(365 * 10, 0, 0, 0, 0)); certGen.SetPublicKey(lastPubKey); int pathLengthConstraint = j + 1; certGen.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(pathLengthConstraint)); certGen.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.KeyCertSign)); X509Certificate certificate; if (rootCert) { ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHECDSA", lastKeyPair.Private, random); certificate = certGen.Generate(signatureFactory); } else { ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHECDSA", caKey.Private, random); certificate = certGen.Generate(signatureFactory); } lastCertIssuer = certificate.IssuerDN; lastPubKey = caKey.Public; lastKeyPair = caKey; certChain.Add(certificate); } // Chain including root, but not AliasCert. NOTE, finishes with CA Helpers.WritePEMObjects(ToPath(Program.DeviceCertChain), certChain.ToArray()); // cert chain including AliasCert (alias cert is first. CA is last) JoinFiles(Program.AliasCert, Program.DeviceCertChain, Program.DeviceCertChainIncAlias); // just the device CA (for the server) Helpers.WritePEMObject(ToPath("DeviceCA.pem"), certChain.Last()); // Now make some certs for the server to use string serverCaName = "CN=Server CA, C=US, O=MSR_TEST"; string serverName = "CN=Server Cert, C=US, O=MSR_TEST"; var serverCA = MakeCertInternal(serverCaName, serverCaName, true, null, null, 1); var serverCert = MakeCertInternal(serverCaName, serverName, false, serverCA.KeyPair, null, 0); Helpers.WritePEMObject(ToPath(Program.ServerCA), serverCA.Certificate); Helpers.WritePEMObjects(ToPath(Program.ServerChain), new Object[] { serverCA.Certificate, serverCert.Certificate }); //Helpers.WritePEMObject(ToPath("T0_ServerCAKey.PEM", serverCA.KeyPair); Helpers.WritePEMObject(ToPath(Program.ServerCert), serverCert.Certificate); Helpers.WritePEMObject(ToPath(Program.ServerKey), serverCert.KeyPair); // OpenSSL needs a file with the Device CA AND the server CA JoinFiles(Program.DeviceCertChain, Program.ServerCA, Program.DeviceCertChainAndServerCA); // OpenSSL test scripts - // print a cert // openssl x509 -text -in T0_ServerCA.pem // Just verify the client chain // openssl verify -purpose sslclient -CAfile T0_DeviceCertChain.PEM DeviceAliasCert.PEM // Just verify the server chain // openssl verify -purpose sslserver -CAfile T0_ServerCA.PEM T0_ServerCert.PEM // openssl s_client -connect localhost: 5556 - cert T0_AliasCert.PEM - key T0_AliasKey.PEM - CAfile T0_DeviceCertChainAndServerCA.PEM // openssl s_client -connect localhost:5556 -cert T0_AliasCert.PEM -key T0_AliasKey.PEM -CAfile T0_DeviceCertChain.PEM // openssl s_server -cert T0_ServerCert.PEM -key T0_ServerKey.PEM -CAfile T0_DeviceCertChainAndServerCA.PEM -status_verbose -verify 10 -rev -accept 5556 return; }
/// <summary> /// Make a new Alias Cert. If refresh=false, a new DevID and Alias are created. If refresh=true /// then just the Alias is created and re-certified using the stored DevID key. /// </summary> /// <param name="refresh"></param> /// <returns></returns> internal DeviceBundle MakeAliasCert(bool refresh, int fwidSeed) { DateTime now = DateTime.Now; byte[] fwid = Helpers.HashData(new byte[1] { (byte)fwidSeed }, 0, 1); const int keyStrength = 256; CryptoApiRandomGenerator rg = new CryptoApiRandomGenerator(); SecureRandom random = new SecureRandom(rg); KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, keyStrength); var keyPairGenerator = new ECKeyPairGenerator(); keyPairGenerator.Init(keyGenerationParameters); AsymmetricCipherKeyPair devIdKey = null; if (refresh) { devIdKey = (AsymmetricCipherKeyPair)Helpers.ReadPemObject(ToPath(Program.DeviceIDPrivate)); } else { devIdKey = keyPairGenerator.GenerateKeyPair(); } // test - remove var oids = new List <Object>() { X509Name.UnstructuredName }; var values = new List <Object>() { "ljkljljklkjlkjlkjlkjlkjlkjlkjlkjlkjljklkjlkjlkjlkjljk" }; X509Name name = new X509Name(oids, values); AsymmetricCipherKeyPair aliasKey = keyPairGenerator.GenerateKeyPair(); // make a string name based on DevID public. Note that the authoritative information // is encoded in the RIoT-extension: this is just for quick-and-dirty device identification. var pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(devIdKey.Public); byte[] pubEncoded = pubInfo.GetDerEncoded(); var pubHashed = Helpers.HashData(pubEncoded, 0, pubEncoded.Length); var shortNameBytes = Helpers.CopyArray(pubHashed, 0, 8); var shortNameString = Helpers.Hexify(shortNameBytes); X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); var serialNumber = new byte[8]; rg.NextBytes(serialNumber); serialNumber[0] &= 0x7F; certGen.SetSerialNumber(new BigInteger(serialNumber)); // The important name-related stuff is encoded in the RIoT extension certGen.SetIssuerDN(new X509Name($"CN=[I]DevID:{shortNameString}, O=MSR_TEST, C=US")); // test REMOVE //certGen.SetSubjectDN(name); certGen.SetSubjectDN(new X509Name($"CN=[S]DevID:{shortNameString}, O=MSR_TEST, C=US")); certGen.SetNotBefore(now); certGen.SetNotAfter(now + new TimeSpan(365 * 10, 0, 0, 0, 0)); certGen.SetPublicKey(aliasKey.Public); // Add the extensions (todo: not sure about KeyUsage.DigitalSiganture certGen.AddExtension(X509Extensions.ExtendedKeyUsage, true, ExtendedKeyUsage.GetInstance(new DerSequence(KeyPurposeID.IdKPClientAuth))); certGen.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature)); AddRIoTExtension(certGen, fwid, devIdKey); // sign it ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHECDSA", devIdKey.Private, random); var certificate = certGen.Generate(signatureFactory); // and return the bundle DeviceBundle bundle = new DeviceBundle { AliasCert = certificate, DeviceIDPublic = devIdKey.Public, AliasKeyPair = aliasKey }; // Just the AliasCert Helpers.WritePEMObject(ToPath(Program.AliasCert), bundle.AliasCert); // The Alias Key Pair Helpers.WritePEMObject(ToPath(Program.AliasKey), bundle.AliasKeyPair); // The encoded DevID Helpers.WritePEMObject(ToPath(Program.DeviceIDPublic), bundle.DeviceIDPublic); // DeviceIDPrivate (just for the update demo) Helpers.WritePEMObject(ToPath(Program.DeviceIDPrivate), devIdKey.Private); return(bundle); }