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); }
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); }
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); }
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); }
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); }
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); }
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++; } }
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); }
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}."); } }