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); }
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(); }
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)); } }
/// <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)); }
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); }); }