private static void CollectCertificate(
     Dictionary <string, HashedCertificate> thumbprintToCertificate,
     HashedCertificate hashedCertificate)
 {
     if (!thumbprintToCertificate.ContainsKey(hashedCertificate.Thumbprint))
     {
         thumbprintToCertificate.Add(hashedCertificate.Thumbprint, hashedCertificate);
     }
 }
 public ExtractedCertificates(
     HashedCertificate signatureEndCertificate,
     IReadOnlyList <HashedCertificate> signatureParentCertificates,
     HashedCertificate timestampEndCertificate,
     IReadOnlyList <HashedCertificate> timestampParentCertificates)
 {
     SignatureEndCertificate     = signatureEndCertificate ?? throw new ArgumentNullException(nameof(signatureEndCertificate));
     SignatureParentCertificates = signatureParentCertificates ?? throw new ArgumentNullException(nameof(signatureParentCertificates));
     TimestampEndCertificate     = timestampEndCertificate ?? throw new ArgumentNullException(nameof(timestampEndCertificate));
     TimestampParentCertificates = timestampParentCertificates ?? throw new ArgumentNullException(nameof(timestampParentCertificates));
 }
        private PackageSignature InitializePackageSignature(
            int packageKey,
            PackageSignatureType type,
            HashedCertificate signatureEndCertificate,
            IReadOnlyDictionary <string, EndCertificate> thumbprintToEndCertificate)
        {
            var packageSignature = new PackageSignature
            {
                CreatedAt         = DateTime.UtcNow,
                EndCertificate    = thumbprintToEndCertificate[signatureEndCertificate.Thumbprint],
                PackageKey        = packageKey,
                Status            = PackageSignatureStatus.Unknown,
                Type              = type,
                TrustedTimestamps = new List <TrustedTimestamp>(),
            };

            packageSignature.EndCertificateKey = packageSignature.EndCertificate.Key;
            _entitiesContext.PackageSignatures.Add(packageSignature);

            return(packageSignature);
        }
        private void ConnectCertificates(
            HashedCertificate endCertificate,
            IReadOnlyCollection <HashedCertificate> parentCertificates,
            IReadOnlyDictionary <string, EndCertificate> thumbprintToEndCertificate,
            IReadOnlyDictionary <string, ParentCertificate> thumbprintToParentCertificates)
        {
            var endCertificateEntity  = thumbprintToEndCertificate[endCertificate.Thumbprint];
            var parentCertificateKeys = new HashSet <long>(endCertificateEntity
                                                           .CertificateChainLinks
                                                           .Select(x => x.ParentCertificateKey));

            foreach (var parentCertificate in parentCertificates)
            {
                var parentCertificateEntity = thumbprintToParentCertificates[parentCertificate.Thumbprint];

                // If either end of the link is new, the link must be new.
                if (endCertificateEntity.Key == default(long) ||
                    parentCertificateEntity.Key == default(long) ||
                    !parentCertificateKeys.Contains(parentCertificateEntity.Key))
                {
                    var link = new CertificateChainLink
                    {
                        EndCertificate    = endCertificateEntity,
                        ParentCertificate = parentCertificateEntity,
                    };
                    _entitiesContext.CertificateChainLinks.Add(link);
                    endCertificateEntity.CertificateChainLinks.Add(link);
                    parentCertificateEntity.CertificateChainLinks.Add(link);

                    if (parentCertificateEntity.Key != default(long))
                    {
                        parentCertificateKeys.Add(parentCertificateEntity.Key);
                    }
                }
            }
        }
 public EndCertificateAndUse(HashedCertificate hashedCertificate, EndCertificateUse endCertificateUse)
 {
     Certificate = hashedCertificate ?? throw new ArgumentNullException(nameof(hashedCertificate));
     Use         = endCertificateUse;
 }
        private void InitializeTrustedTimestamp(
            PackageSignature packageSignature,
            Signature signature,
            HashedCertificate timestampEndCertificate,
            IReadOnlyDictionary <string, EndCertificate> thumbprintToEndCertificate)
        {
            if (packageSignature.TrustedTimestamps.Count > 1)
            {
                _logger.LogError(
                    "There are {Count} trusted timestamps for the {SignatureType} signature on package {PackageKey}. There should be either zero or one.",
                    packageSignature.TrustedTimestamps.Count,
                    signature.Type,
                    packageSignature.PackageKey);

                throw new InvalidOperationException("There should never be more than one trusted timestamp per package signature.");
            }

            // Determine the value of the timestamp.
            var value = signature.Timestamps.Single().UpperLimit.UtcDateTime;

            TrustedTimestamp trustedTimestamp;

            if (packageSignature.TrustedTimestamps.Count == 0)
            {
                trustedTimestamp = new TrustedTimestamp
                {
                    PackageSignature    = packageSignature,
                    PackageSignatureKey = packageSignature.Key,
                    EndCertificate      = thumbprintToEndCertificate[timestampEndCertificate.Thumbprint],
                    Value  = value,
                    Status = TrustedTimestampStatus.Valid,
                };
                trustedTimestamp.EndCertificateKey = trustedTimestamp.EndCertificate.Key;
                packageSignature.TrustedTimestamps.Add(trustedTimestamp);
                _entitiesContext.TrustedTimestamps.Add(trustedTimestamp);
            }
            else
            {
                trustedTimestamp = packageSignature.TrustedTimestamps.Single();

                if (trustedTimestamp.EndCertificate.Thumbprint != timestampEndCertificate.Thumbprint)
                {
                    _logger.LogError(
                        "The timestamp end certificate thumbprint cannot change for the {SignatureType} signature " +
                        "on package {PackageKey}. The existing timestamp end certificate is {ExistingThumbprint}. " +
                        "The new thumprint is {NewThumbprint}.",
                        signature.Type,
                        packageSignature.PackageKey,
                        packageSignature.EndCertificate.Thumbprint,
                        timestampEndCertificate.Thumbprint);

                    throw new InvalidOperationException("The thumbprint of the timestamp end certificate cannot change.");
                }

                if (trustedTimestamp.Value != value)
                {
                    _logger.LogError(
                        "The trusted timestamp value cannot change for the {SignatureType} signature on package " +
                        "{PackageKey}. The existing timestamp value is {ExistingValue}. The new value is {NewValue}.",
                        signature.Type,
                        packageSignature.PackageKey,
                        trustedTimestamp.Value,
                        value);

                    throw new InvalidOperationException("The value of the trusted timestamp cannot change.");
                }
            }
        }
        private async Task <PackageSignature> InitializePackageSignatureAsync(
            int packageKey,
            PackageSignatureType type,
            HashedCertificate signatureEndCertificate,
            IReadOnlyDictionary <string, EndCertificate> thumbprintToEndCertificate,
            bool replacePackageSignature)
        {
            var packageSignatures = await _entitiesContext
                                    .PackageSignatures
                                    .Include(x => x.TrustedTimestamps)
                                    .Include(x => x.EndCertificate)
                                    .Where(x => x.PackageKey == packageKey && x.Type == type)
                                    .ToListAsync();

            if (packageSignatures.Count > 1)
            {
                _logger.LogError(
                    "There are {Count} package signatures for package key {PackageKey} and type {Type}. There should be either zero or one.",
                    packageSignatures.Count,
                    packageKey,
                    type);

                throw new InvalidOperationException("There should never be more than one package signature per package and signature type.");
            }

            PackageSignature packageSignature;

            if (packageSignatures.Count == 0)
            {
                packageSignature = InitializePackageSignature(
                    packageKey,
                    type,
                    signatureEndCertificate,
                    thumbprintToEndCertificate);
            }
            else
            {
                packageSignature = packageSignatures.Single();

                if (packageSignature.EndCertificate.Thumbprint != signatureEndCertificate.Thumbprint)
                {
                    if (replacePackageSignature)
                    {
                        _logger.LogWarning(
                            "The signature end certificate thumbprint has changed for package {PackageKey} and type " +
                            "{Type}. The previous signature end certificate is {ExistingThumbprint}. The new thumprint " +
                            "is {NewThumbprint}. The previous record with key {PackageSignatureKey} will be removed.",
                            packageKey,
                            type,
                            packageSignature.EndCertificate.Thumbprint,
                            signatureEndCertificate.Thumbprint,
                            packageSignature.Key);

                        // Remove the child trusted timestamps. This should be handled by cascading delete but to be
                        // explicit and to facilitate unit testing, we explicitly remove them.
                        foreach (var trustedTimestamp in packageSignature.TrustedTimestamps)
                        {
                            _entitiesContext.TrustedTimestamps.Remove(trustedTimestamp);
                        }

                        _entitiesContext.PackageSignatures.Remove(packageSignature);

                        packageSignature = InitializePackageSignature(
                            packageKey,
                            type,
                            signatureEndCertificate,
                            thumbprintToEndCertificate);
                    }
                    else
                    {
                        _logger.LogError(
                            "The signature end certificate thumbprint cannot change for package {PackageKey} and type " +
                            "{Type}. The existing signature end certificate is {ExistingThumbprint}. The new thumprint " +
                            "is {NewThumbprint}.",
                            packageKey,
                            type,
                            packageSignature.EndCertificate.Thumbprint,
                            signatureEndCertificate.Thumbprint);

                        throw new InvalidOperationException("The thumbprint of the signature end certificate cannot change.");
                    }
                }
            }

            return(packageSignature);
        }