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;
        }
예제 #2
0
        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);
        }