示例#1
0
        public void AsSecret_Minimal_Roundtrip()
        {
            var systemBuid = Guid.NewGuid().ToString();
            var key        = Convert.FromBase64String(
                "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JR0pBb0dCQUorNXVIQjJycllw" +
                "VEt4SWNGUnJxR1ZqTHRNQ2wyWHhmTVhJeEhYTURrM01jV2hxK2RtWkcvWW0KeDJuTGZq" +
                "WWJPeUduQ1BxQktxcUU5Q2tyQy9DUi9mTlgwNjJqMU1pUHJYY2RnQ0tiNzB2bmVlMFNF" +
                "T2FmNVhEQworZWFZeGdjWTYvbjBXODNrSklXMGF0czhMWmUwTW9XNXpXSTh6cnM4eDIw" +
                "UFFJK1RGU1p4QWdNQkFBRT0KLS0tLS1FTkQgUlNBIFBVQkxJQyBLRVktLS0tLQo=");

            var pairingRecord = new PairingRecordGenerator().Generate(key, systemBuid);
            var secret        = V1SecretExtensions.AsSecret(pairingRecord);

            Assert.NotNull(secret.Data["ca.crt"]);
            Assert.NotNull(secret.Data["ca.key"]);
            Assert.NotNull(secret.Data["tls.crt"]);
            Assert.NotNull(secret.Data["tls.key"]);
            Assert.NotNull(secret.Data["device.crt"]);

            Assert.NotNull(secret.Data["hostId"]);
            Assert.NotNull(secret.Data["systemBuid"]);

            var roundtripRecord = V1SecretExtensions.AsPairingRecord(secret);

            Assert.Equal(pairingRecord.DeviceCertificate, roundtripRecord.DeviceCertificate);
            Assert.Equal(pairingRecord.RootCertificate, roundtripRecord.RootCertificate);
            Assert.Equal(pairingRecord.RootPrivateKey.ExportPkcs8PrivateKey(), roundtripRecord.RootPrivateKey.ExportPkcs8PrivateKey());
            Assert.Equal(pairingRecord.HostCertificate, roundtripRecord.HostCertificate);
            Assert.Equal(pairingRecord.HostPrivateKey.ExportPkcs8PrivateKey(), roundtripRecord.HostPrivateKey.ExportPkcs8PrivateKey());
            Assert.Equal(pairingRecord.HostId, roundtripRecord.HostId);
            Assert.Equal(pairingRecord.SystemBUID, roundtripRecord.SystemBUID);
            Assert.Null(roundtripRecord.EscrowBag);
            Assert.Null(roundtripRecord.WiFiMacAddress);
        }
示例#2
0
        public async Task ReadAsync_Works_Async()
        {
            var key = Convert.FromBase64String(
                "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JR0pBb0dCQUorNXVIQjJycllw" +
                "VEt4SWNGUnJxR1ZqTHRNQ2wyWHhmTVhJeEhYTURrM01jV2hxK2RtWkcvWW0KeDJuTGZq" +
                "WWJPeUduQ1BxQktxcUU5Q2tyQy9DUi9mTlgwNjJqMU1pUHJYY2RnQ0tiNzB2bmVlMFNF" +
                "T2FmNVhEQworZWFZeGdjWTYvbjBXODNrSklXMGF0czhMWmUwTW9XNXpXSTh6cnM4eDIw" +
                "UFFJK1RGU1p4QWdNQkFBRT0KLS0tLS1FTkQgUlNBIFBVQkxJQyBLRVktLS0tLQo=");

            var pairingRecord = new PairingRecordGenerator().Generate(key, "abc");
            var secret        = pairingRecord.AsSecret();

            var client       = new Mock <KubernetesClient>(MockBehavior.Strict);
            var secretClient = new Mock <NamespacedKubernetesClient <V1Secret> >(MockBehavior.Strict);

            client.Setup(c => c.GetClient <V1Secret>()).Returns(secretClient.Object);

            secretClient
            .Setup(c => c.TryReadAsync("abc", default))
            .Returns(Task.FromResult(secret))
            .Verifiable();

            var store = new KubernetesPairingRecordStore(client.Object, NullLogger <KubernetesPairingRecordStore> .Instance);

            var value = await store.ReadAsync("abc", default);

            // Basic assertions
            Assert.NotNull(value.DeviceCertificate);
            Assert.NotNull(value.HostCertificate);
            Assert.NotNull(value.RootCertificate);

            secretClient.Verify();
        }
示例#3
0
        public async Task PairingRecord_Lifecycle_Async()
        {
            var key = Convert.FromBase64String(
                "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JR0pBb0dCQUorNXVIQjJycllw" +
                "VEt4SWNGUnJxR1ZqTHRNQ2wyWHhmTVhJeEhYTURrM01jV2hxK2RtWkcvWW0KeDJuTGZq" +
                "WWJPeUduQ1BxQktxcUU5Q2tyQy9DUi9mTlgwNjJqMU1pUHJYY2RnQ0tiNzB2bmVlMFNF" +
                "T2FmNVhEQworZWFZeGdjWTYvbjBXODNrSklXMGF0czhMWmUwTW9XNXpXSTh6cnM4eDIw" +
                "UFFJK1RGU1p4QWdNQkFBRT0KLS0tLS1FTkQgUlNBIFBVQkxJQyBLRVktLS0tLQo=");

            var udid = "pairingrecord-lifecycle";
            var buid = Guid.NewGuid().ToString();

            var record = new PairingRecordGenerator().Generate(key, buid);

            using (var client = this.CreateKubernetesClient())
            {
                var store = new KubernetesPairingRecordStore(client, this.loggerFactory.CreateLogger <KubernetesPairingRecordStore>());

                // The record should not exist.
                Assert.Null(await store.ReadAsync(udid, default).ConfigureAwait(false));

                // Write the record; it can be retrieved afterwards
                await store.WriteAsync(udid, record, default).ConfigureAwait(false);

                var record2 = await store.ReadAsync(udid, default).ConfigureAwait(false);

                Assert.NotNull(record2);
                Assert.Equal(record.ToByteArray(), record2.ToByteArray());

                // Delete the record; it can no longer be retrieved afterwardss
                await store.DeleteAsync(udid, default).ConfigureAwait(false);

                Assert.Null(await store.ReadAsync(udid, default).ConfigureAwait(false));
            }
        }
示例#4
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PairingWorker"/> class.
 /// </summary>
 /// <param name="muxerClient">
 /// A <see cref="MuxerClient"/> which can be used to interact with the muxer.
 /// </param>
 /// <param name="context">
 /// The device context.
 /// </param>
 /// <param name="lockdownClientFactory">
 /// A <see cref="LockdownClientFactory"/> which can be used to construct a lockdown client.
 /// </param>
 /// <param name="notificationProxyClientFactory">
 /// A <see cref="NotificationProxyClientFactory"/> which can be used to construct a notification proxy client.
 /// </param>
 /// <param name="pairingRecordGenerator">
 /// A <see cref="pairingRecordGenerator"/> which can be used to generate a pairing record.
 /// </param>
 public PairingWorker(
     MuxerClient muxerClient,
     DeviceContext context,
     ClientFactory <LockdownClient> lockdownClientFactory,
     ClientFactory <NotificationProxyClient> notificationProxyClientFactory,
     PairingRecordGenerator pairingRecordGenerator)
 {
     this.muxer   = muxerClient ?? throw new ArgumentNullException(nameof(muxerClient));
     this.context = context ?? throw new ArgumentNullException(nameof(context));
     this.notificationProxyClientFactory = notificationProxyClientFactory ?? throw new ArgumentNullException(nameof(notificationProxyClientFactory));
     this.lockdownClientFactory          = lockdownClientFactory ?? throw new ArgumentNullException(nameof(lockdownClientFactory));
     this.pairingRecordGenerator         = pairingRecordGenerator ?? throw new ArgumentNullException(nameof(pairingRecordGenerator));
 }
示例#5
0
        public void Generate_GeneratesValidPair()
        {
            string udid   = null;
            string caName = string.Empty;

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                udid   = "my-udid";
                caName = "CN=Root Certification Authority, OU=my-udid";
            }

            var key = Convert.FromBase64String(
                "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJDZ0tDQVFFQTBuNEJrdUM5" +
                "M0NJajJtUWxXSkQxWVVpaDgrTUsxbEdSS0ZlMStrQjE2aG5iOG5iL0tMazIKNHE4Y1Jq" +
                "aTArRVUxQlNDOGJxK2RjcHhSMlFvWnU1UWJiRUZBWjVxSXBqa082WUhWYjJwWVYwRXBP" +
                "cnVsZVQyLwpXSEI2YUZYdnU2RkRETEJjVktwUjVodlRBZk01UkxxTllkNGJmWXdVdnhE" +
                "MWI4QkJMK3VSVno1YnorK28zazBsCjB1QU02VjdqL3Fobkp6YTRKMDdiMFN6WlRwNUE3" +
                "T1VVUWV5UEE4UDVhMWpORklua2Joc1FTZ3RFejV2cHk4OWEKY3FMektMQ3ZocjJhY0dB" +
                "djRCT2lQLzh0TWdpa0lnVktGbWJ3bFU1dW5RbmNQYllmN2NoTmRmZnE3dEdRcVdFagpD" +
                "QUhidUx6M1VWOHpDdG5wOFNiUzRBWmFnNkR6dzMrakJRSURBUUFCCi0tLS0tRU5EIFJT" +
                "QSBQVUJMSUMgS0VZLS0tLS0=");

            var pairingRecord = new PairingRecordGenerator().Generate(key, udid, "system-buid");

            Assert.NotNull(pairingRecord.DeviceCertificate);
            Assert.NotNull(pairingRecord.HostCertificate);
            Assert.NotNull(pairingRecord.HostId);
            Assert.NotNull(pairingRecord.HostPrivateKey);
            Assert.NotNull(pairingRecord.RootCertificate);
            Assert.NotNull(pairingRecord.RootPrivateKey);

            // The host ID must be a well-formed, upper-case UUID
            Assert.True(Guid.TryParse(pairingRecord.HostId, out Guid hostId));
            Assert.Equal(hostId.ToString("D").ToUpperInvariant(), pairingRecord.HostId);

            var rootSubjectKeyIdentifier = pairingRecord.RootCertificate.Extensions.OfType <X509SubjectKeyIdentifierExtension>().Single();

            // Validate the root certificate
            Assert.Equal(caName, pairingRecord.RootCertificate.Subject);
            Assert.Equal(caName, pairingRecord.RootCertificate.Issuer);
            Assert.Equal("00", pairingRecord.RootCertificate.SerialNumber);
            Assert.Equal(2048, pairingRecord.RootCertificate.PublicKey.Key.KeySize);
            Assert.Equal("RSA", pairingRecord.RootCertificate.PublicKey.Key.SignatureAlgorithm);
            Assert.Equal("sha1RSA", pairingRecord.RootCertificate.SignatureAlgorithm.FriendlyName);
            Assert.Equal(3, pairingRecord.RootCertificate.Version);
            Assert.Equal(pairingRecord.RootCertificate.NotAfter.ToUniversalTime().AddDays(-10 * 365), pairingRecord.RootCertificate.NotBefore.ToUniversalTime());

            Assert.Collection(
                pairingRecord.RootCertificate.Extensions.Cast <X509Extension>(),
                (extension) =>
            {
                var basicConstraintsExtension = Assert.IsType <X509BasicConstraintsExtension>(extension);
                Assert.True(basicConstraintsExtension.CertificateAuthority);
                Assert.True(basicConstraintsExtension.Critical);
            },
                (extension) =>
            {
                var subjectKeyIdentifierExtension = Assert.IsType <X509SubjectKeyIdentifierExtension>(extension);
                Assert.NotNull(subjectKeyIdentifierExtension.SubjectKeyIdentifier);
                Assert.False(subjectKeyIdentifierExtension.Critical);
            });

            // Validate the host certificate
            Assert.Equal(string.Empty, pairingRecord.HostCertificate.Subject);
            Assert.Equal(caName, pairingRecord.HostCertificate.Issuer);
            Assert.Equal("00", pairingRecord.HostCertificate.SerialNumber);
            Assert.Equal(2048, pairingRecord.HostCertificate.PublicKey.Key.KeySize);
            Assert.Equal("RSA", pairingRecord.HostCertificate.PublicKey.Key.SignatureAlgorithm);
            Assert.Equal("sha1RSA", pairingRecord.RootCertificate.SignatureAlgorithm.FriendlyName);
            Assert.Equal(3, pairingRecord.HostCertificate.Version);
            Assert.Equal(
                pairingRecord.HostCertificate.NotAfter.ToUniversalTime().AddDays(-10 * 365),
                pairingRecord.HostCertificate.NotBefore.ToUniversalTime());

            Assert.True(IsTrusted(pairingRecord.RootCertificate, pairingRecord.HostCertificate));

            Assert.Collection(
                pairingRecord.HostCertificate.Extensions.Cast <X509Extension>(),
                (extension) =>
            {
                var basicConstraintsExtension = Assert.IsType <X509BasicConstraintsExtension>(extension);
                Assert.False(basicConstraintsExtension.CertificateAuthority);
                Assert.True(basicConstraintsExtension.Critical);
            },
                (extension) =>
            {
                var subjectKeyIdentifierExtension = Assert.IsType <X509SubjectKeyIdentifierExtension>(extension);
                Assert.NotNull(subjectKeyIdentifierExtension.SubjectKeyIdentifier);
                Assert.False(subjectKeyIdentifierExtension.Critical);
            },
                (extension) =>
            {
                var keyUsageExtension = Assert.IsType <X509KeyUsageExtension>(extension);
                Assert.Equal(X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, keyUsageExtension.KeyUsages);
                Assert.True(keyUsageExtension.Critical);
            });

            // Validate the device certificate
            Assert.Equal(string.Empty, pairingRecord.DeviceCertificate.Subject);
            Assert.Equal(caName, pairingRecord.DeviceCertificate.Issuer);
            Assert.Equal("00", pairingRecord.DeviceCertificate.SerialNumber);
            Assert.Equal(2048, pairingRecord.DeviceCertificate.PublicKey.Key.KeySize);
            Assert.Equal("RSA", pairingRecord.DeviceCertificate.PublicKey.Key.SignatureAlgorithm);
            Assert.Equal("sha1RSA", pairingRecord.RootCertificate.SignatureAlgorithm.FriendlyName);
            Assert.Equal(3, pairingRecord.DeviceCertificate.Version);
            Assert.Equal(
                pairingRecord.DeviceCertificate.NotAfter.ToUniversalTime().AddDays(-10 * 365),
                pairingRecord.DeviceCertificate.NotBefore.ToUniversalTime());

            Assert.True(IsTrusted(pairingRecord.RootCertificate, pairingRecord.DeviceCertificate));

            Assert.Collection(
                pairingRecord.DeviceCertificate.Extensions.Cast <X509Extension>(),
                (extension) =>
            {
                var basicConstraintsExtension = Assert.IsType <X509BasicConstraintsExtension>(extension);
                Assert.False(basicConstraintsExtension.CertificateAuthority);
                Assert.True(basicConstraintsExtension.Critical);
            },
                (extension) =>
            {
                var subjectKeyIdentifierExtension = Assert.IsType <X509SubjectKeyIdentifierExtension>(extension);
                Assert.NotNull(subjectKeyIdentifierExtension.SubjectKeyIdentifier);
                Assert.False(subjectKeyIdentifierExtension.Critical);
            },
                (extension) =>
            {
                var keyUsageExtension = Assert.IsType <X509KeyUsageExtension>(extension);
                Assert.Equal(X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, keyUsageExtension.KeyUsages);
                Assert.True(keyUsageExtension.Critical);
            });
        }