コード例 #1
0
        public void CreateSignedFileAsync_HaveData_ShouldContainBinAndSigFiles()
        {
            ExposureBatchFileUtil utils = new ExposureBatchFileUtil(_pemFilePath);
            var returnStream            = utils.CreateSignedFileAsync(_exportBatch);

            returnStream.Wait();
            var result = returnStream.Result;

            Assert.IsNotNull(result);

            List <string> fileNameInZipStreams = new List <string>();
            List <string> expectFileNameInZip  = new List <string>()
            {
                "export.bin", "export.sig"
            };

            using (var archive = new ZipArchive(result))
            {
                var entries = archive.Entries;
                foreach (ZipArchiveEntry entry in entries)
                {
                    fileNameInZipStreams.Add(entry.Name);
                }
            }
            CollectionAssert.AreEqual(expectFileNameInZip, fileNameInZipStreams);
        }
コード例 #2
0
        public void SignData_WithValidKeys_ShouldReturnValidSignature()
        {
            byte[] sampleData = Encoding.UTF8.GetBytes("sample data");
            var    signedData = ExposureBatchFileUtil.SignData(sampleData, _pemKeyFromGoogle);
            var    valid      = VerifySignedData(sampleData, signedData, _pemPublicKeyFromGoogle);

            Assert.AreEqual(valid, true);
        }
コード例 #3
0
        public async Task CanCreateStream()
        {
            var export = Utils.GenerateTemporaryExposureKeyExport(10);

            using var stream = await ExposureBatchFileUtil.CreateSignedFileAsync(export, TestSignatures);

            Assert.NotNull(stream);
            Assert.NotEqual(0, stream.Length);
        }
コード例 #4
0
        public Stream ExportDiagnosisKeys(IList <TemporaryExposureKey> keys)
        {
            var exportBatch = _exposureKeyMapper.FromEntityToProtoBatch(keys);
            var exportUtil  = new ExposureBatchFileUtil(_appSettingsConfig.ZipCertificatePath);
            var task        = exportUtil.CreateSignedFileAsync(exportBatch);

            task.Wait();
            return(task.Result);
        }
コード例 #5
0
        public async Task ValidateFile()
        {
            var expectedExport = GenerateRandomExport();

            using var stream = await ExposureBatchFileUtil.CreateSignedFileAsync(expectedExport, TestSignatures);

            using var zipFile = new ZipArchive(stream);

            var expectedEntries = new[] { "export.bin", "export.sig" };
            var entries         = zipFile.Entries.Select(e => e.FullName);

            Assert.Equal(expectedEntries, entries);
        }
コード例 #6
0
        public async Task CreateSignedFileAddsHeaderToBin()
        {
            var export = Utils.GenerateTemporaryExposureKeyExport(10);

            using var stream = await ExposureBatchFileUtil.CreateSignedFileAsync(export, TestSignatures);

            using var zip = new ZipArchive(stream);

            using var bin = zip.GetBin(false);

            var header = new byte[16];

            bin.Read(header);
            Assert.Equal(TemporaryExposureKeyExport.Header, header);
        }
コード例 #7
0
        public async Task CanCreateStreamFromDbItems()
        {
            var expectedExport = GenerateRandomExport();

            using var stream = await ExposureBatchFileUtil.CreateSignedFileAsync(expectedExport, TestSignatures);

            Assert.NotNull(stream);

            using var zip       = new ZipArchive(stream);
            using var exportBin = zip.GetBin();

            var actualExport = TemporaryExposureKeyExport.Parser.ParseFrom(exportBin);

            Assert.Equal(expectedExport.Keys, actualExport.Keys);
        }
コード例 #8
0
        public void CreateBinAsync_PassData_ShouldReturnStreamWithCorrectHeader()
        {
            var returnStream = ExposureBatchFileUtil.CreateBinAsync(_exportBatch);

            returnStream.Wait();
            var result = returnStream.Result;

            Assert.IsNotNull(result);

            StreamReader sr             = new StreamReader(result);
            string       content        = sr.ReadToEnd();
            string       HeaderContents = "EK Export v1    ";

            Assert.AreEqual(HeaderContents, content.Substring(0, 16));
        }
コード例 #9
0
        public async Task ValidateFileBinary()
        {
            var expectedExport = GenerateRandomExport();

            using var stream = await ExposureBatchFileUtil.CreateSignedFileAsync(expectedExport, TestSignatures);

            using var zipFile   = new ZipArchive(stream);
            using var exportBin = zipFile.GetBin();

            var export = TemporaryExposureKeyExport.Parser.ParseFrom(exportBin);

            Assert.NotNull(export);

            var info = Assert.Single(export.SignatureInfos);

            Assert.Equal("1.2.840.10045.4.3.2", info.SignatureAlgorithm);
            Assert.Equal("TestServer", info.VerificationKeyId);
            Assert.Equal("2", info.VerificationKeyVersion);
        }
        public void CreateSignedFileAsync_HaveData_AppDeserializationEqualsOriginalKeys()
        {
            // Arrange
            var utils = new ExposureBatchFileUtil(_pemFilePath);

            // Act
            var returnStream = utils.CreateSignedFileAsync(_exportBatch);

            returnStream.Wait();
            var result = returnStream.Result;

            // Assert
            Assert.IsNotNull(result);

            // Arrange
            using var archive = new ZipArchive(result);

            // Act
            var tempExposureKeyExport = ZipToTemporaryExposureKeyExport(archive);

            // Assert
            var keys = tempExposureKeyExport.Keys;

            using var enumerator = keys.GetEnumerator();
            var i = 0;

            while (enumerator.MoveNext())
            {
                var current  = enumerator.Current;
                var batchKey = _exportBatch.Keys[i];
                Assert.AreEqual(current.RollingStartIntervalNumber, batchKey.RollingStartIntervalNumber);
                Assert.AreEqual(current.RollingPeriod, batchKey.RollingPeriod);
                Assert.AreEqual(current.KeyData, batchKey.KeyData);
                Assert.AreEqual(current.DaysSinceOnsetOfSymptoms, batchKey.DaysSinceOnsetOfSymptoms);
                Assert.AreEqual(current.ReportType, batchKey.ReportType);
                i++;
            }
        }
コード例 #11
0
        public async Task ValidateFileSignature()
        {
            var expectedExport = GenerateRandomExport();

            using var stream = await ExposureBatchFileUtil.CreateSignedFileAsync(expectedExport, TestSignatures);

            using var zipFile   = new ZipArchive(stream);
            using var exportSig = zipFile.GetSignature();

            var signatureList = TEKSignatureList.Parser.ParseFrom(exportSig);

            Assert.NotNull(signatureList);

            var signature = Assert.Single(signatureList.Signatures);

            Assert.NotEmpty(signature.Signature.ToByteArray());

            var info = signature.SignatureInfo;

            Assert.Equal("1.2.840.10045.4.3.2", info.SignatureAlgorithm);
            Assert.Equal("TestServer", info.VerificationKeyId);
            Assert.Equal("2", info.VerificationKeyVersion);
        }
コード例 #12
0
        async Task CreateBatchFiles(ILogger logger)
        {
            var supportedRegions = settings.Value.SupportedRegions;

            if (supportedRegions?.Any() != true)
            {
                logger.LogWarning("No supported regions.");
            }

            var cloudStorageAccount = CloudStorageAccount.Parse(settings.Value.BlobStorageConnectionString);
            var cloudBlobClient     = cloudStorageAccount.CreateCloudBlobClient();

            foreach (var region in supportedRegions)
            {
                if (!await storage.HasKeysAsync(region))
                {
                    logger.LogInformation("No keys found for region '{0}'.", region);
                    continue;
                }

                // We base the container name off a global configurable prefix
                // and also the region name, so we end up having one container per
                // region which can help with azure scaling/region allocation
                var containerName = $"{settings.Value.BlobStorageContainerNamePrefix}{region.ToLowerInvariant()}";

                logger.LogInformation("Batch may be saved to container '{0}'.", containerName);

                // Get our container
                var cloudBlobContainer = cloudBlobClient.GetContainerReference(containerName);

                // Make sure the container exists
                await cloudBlobContainer.CreateIfNotExistsAsync(BlobContainerPublicAccessType.Container, new BlobRequestOptions(), new OperationContext());

                // Find all the root level directories
                var rootBlobs = cloudBlobContainer.ListBlobs()
                                .Where(b => string.IsNullOrEmpty(b.Parent?.Prefix))
                                .OfType <CloudBlobDirectory>()
                                .ToList();

                var highestDirNumber = 0;

                foreach (var rb in rootBlobs)
                {
                    var trimmedPrefix = rb.Prefix.Trim('/');

                    if (trimmedPrefix.Contains('/'))
                    {
                        continue;
                    }

                    if (int.TryParse(trimmedPrefix, out var num))
                    {
                        highestDirNumber = Math.Max(highestDirNumber, num);
                    }
                }

                // Actual next is plus one
                var nextDirNumber = highestDirNumber + 1;

                logger.LogInformation("Batch may be saved to path '{0}/{1}'.", containerName, nextDirNumber);

                // Load all signer infos
                var signerInfos = await storage.GetAllSignerInfosAsync();

                var batchesCount   = 0;
                var batchFileCount = 0;

                do
                {
                    // Create batch files from all the keys in the database
                    batchFileCount = await storage.CreateBatchFilesAsync(region, settings.Value.MaxFilesPerBatch, async export =>
                    {
                        // Don't process a batch without keys
                        if (export == null || (export.Keys != null && export.Keys.Count() <= 0))
                        {
                            logger.LogWarning("For some reason, a batch was started when there were no keys to put in that batch...");
                            return;
                        }

                        // Filename is inferable as batch number
                        var batchFileName = $"{nextDirNumber}/{export.BatchNum}.dat";

                        var blockBlob = cloudBlobContainer.GetBlockBlobReference(batchFileName);

                        // Write the proto buf to a memory stream
                        using var signedFileStream = await ExposureBatchFileUtil.CreateSignedFileAsync(export, signerInfos);

                        // Set the batch number and region as metadata
                        blockBlob.Metadata[dirNumberMetadataKey]   = nextDirNumber.ToString();
                        blockBlob.Metadata[batchNumberMetadataKey] = export.BatchNum.ToString();
                        blockBlob.Metadata[batchRegionMetadataKey] = region;

                        await blockBlob.UploadFromStreamAsync(signedFileStream);
                        await blockBlob.SetMetadataAsync();

                        logger.LogInformation($"Saved batch file '{export.BatchNum}/{export.BatchSize}' to '{containerName}/{nextDirNumber}/{export.BatchNum}.dat'.");
                    });

                    logger.LogInformation($"Saved {batchFileCount} batch files to '{containerName}/{nextDirNumber}/'.");

                    if (batchFileCount > 0)
                    {
                        // Increment our dir number for the next batch to be created
                        nextDirNumber++;
                        batchesCount++;
                    }
                } while (batchFileCount > 0);

                logger.LogInformation($"Saved {batchesCount} batches for {region}.");
            }
        }