예제 #1
0
        private static bool CertMatchesIds(X509Certificate2 signerCert, EssCertId certId, EssCertIdV2 certId2)
        {
            Debug.Assert(signerCert != null);
            Debug.Assert(certId != null || certId2 != null);
            byte[] serialNumber = null;

            if (certId != null)
            {
                Span <byte> thumbprint = stackalloc byte[20];

                if (!signerCert.TryGetCertHash(HashAlgorithmName.SHA1, thumbprint, out int written) ||
                    written != thumbprint.Length ||
                    !thumbprint.SequenceEqual(certId.Hash.Span))
                {
                    return(false);
                }

                if (certId.IssuerSerial != null)
                {
                    serialNumber = signerCert.GetSerialNumber();
                    Array.Reverse(serialNumber);

                    if (!IssuerAndSerialMatch(
                            certId.IssuerSerial.Value,
                            signerCert.IssuerName.RawData,
                            serialNumber))
                    {
                        return(false);
                    }
                }
            }

            if (certId2 != null)
            {
                HashAlgorithmName alg;
                // SHA-2-512 is the biggest we know about.
                Span <byte> thumbprint = stackalloc byte[512 / 8];

                try
                {
                    alg = Helpers.GetDigestAlgorithm(certId2.HashAlgorithm.Algorithm);

                    if (signerCert.TryGetCertHash(alg, thumbprint, out int written))
                    {
                        thumbprint = thumbprint.Slice(0, written);
                    }
                    else
                    {
                        Debug.Fail(
                            $"TryGetCertHash did not fit in {thumbprint.Length} for hash {certId2.HashAlgorithm.Algorithm.Value}");

                        thumbprint = signerCert.GetCertHash(alg);
                    }
                }
                catch (CryptographicException)
                {
                    return(false);
                }

                if (!thumbprint.SequenceEqual(certId2.Hash.Span))
                {
                    return(false);
                }

                if (certId2.IssuerSerial != null)
                {
                    if (serialNumber == null)
                    {
                        serialNumber = signerCert.GetSerialNumber();
                        Array.Reverse(serialNumber);
                    }

                    if (!IssuerAndSerialMatch(
                            certId2.IssuerSerial.Value,
                            signerCert.IssuerName.RawData,
                            serialNumber))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
예제 #2
0
        private static bool TryGetCertIds(SignerInfo signer, out EssCertId certId, out EssCertIdV2 certId2)
        {
            // RFC 5035 says that SigningCertificateV2 (contains ESSCertIDv2) is a signed
            // attribute, with OID 1.2.840.113549.1.9.16.2.47, and that it must not be multiply defined.

            // RFC 2634 says that SigningCertificate (contains ESSCertID) is a signed attribute,
            // with OID 1.2.840.113549.1.9.16.2.12, and that it must not be multiply defined.
            certId  = null;
            certId2 = null;

            foreach (CryptographicAttributeObject attrSet in signer.SignedAttributes)
            {
                string setOid = attrSet.Oid?.Value;

                if (setOid != null &&
                    setOid != Oids.SigningCertificate &&
                    setOid != Oids.SigningCertificateV2)
                {
                    continue;
                }

                foreach (AsnEncodedData attr in attrSet.Values)
                {
                    string attrOid = attr.Oid?.Value;

                    if (attrOid == Oids.SigningCertificate)
                    {
                        if (certId != null)
                        {
                            return(false);
                        }

                        try
                        {
                            SigningCertificateAsn signingCert =
                                AsnSerializer.Deserialize <SigningCertificateAsn>(attr.RawData, AsnEncodingRules.BER);

                            if (signingCert.Certs.Length < 1)
                            {
                                return(false);
                            }

                            // The first one is the signing cert, the rest constrain the chain.
                            certId = signingCert.Certs[0];
                        }
                        catch (CryptographicException)
                        {
                            return(false);
                        }
                    }

                    if (attrOid == Oids.SigningCertificateV2)
                    {
                        if (certId2 != null)
                        {
                            return(false);
                        }

                        try
                        {
                            SigningCertificateV2Asn signingCert =
                                AsnSerializer.Deserialize <SigningCertificateV2Asn>(attr.RawData, AsnEncodingRules.BER);

                            if (signingCert.Certs.Length < 1)
                            {
                                return(false);
                            }

                            // The first one is the signing cert, the rest constrain the chain.
                            certId2 = signingCert.Certs[0];
                        }
                        catch (CryptographicException)
                        {
                            return(false);
                        }
                    }
                }
            }

            return(certId2 != null || certId != null);
        }
예제 #3
0
        private static bool CheckCertificate(
            X509Certificate2 tsaCertificate,
            SignerInfo signer,
            EssCertId certId,
            EssCertIdV2 certId2,
            Rfc3161TimestampTokenInfo tokenInfo)
        {
            Debug.Assert(tsaCertificate != null);
            Debug.Assert(signer != null);
            Debug.Assert(tokenInfo != null);
            // certId and certId2 are allowed to be null, they get checked in CertMatchesIds.

            if (!CertMatchesIds(tsaCertificate, certId, certId2))
            {
                return(false);
            }

            // Nothing in RFC3161 actually mentions checking the certificate's validity
            // against the TSTInfo timestamp value, but it seems sensible.
            //
            // Accuracy is ignored here, for better replicability in user code.

            if (tsaCertificate.NotAfter < tokenInfo.Timestamp ||
                tsaCertificate.NotBefore > tokenInfo.Timestamp)
            {
                return(false);
            }

            // https://tools.ietf.org/html/rfc3161#section-2.3
            //
            // The TSA MUST sign each time-stamp message with a key reserved
            // specifically for that purpose.  A TSA MAY have distinct private keys,
            // e.g., to accommodate different policies, different algorithms,
            // different private key sizes or to increase the performance. The
            // corresponding certificate MUST contain only one instance of the
            // extended key usage field extension as defined in [RFC2459] Section
            // 4.2.1.13 with KeyPurposeID having value:
            //
            // id-kp-timeStamping. This extension MUST be critical.

            using (var ekuExts = tsaCertificate.Extensions.OfType <X509EnhancedKeyUsageExtension>().GetEnumerator())
            {
                if (!ekuExts.MoveNext())
                {
                    return(false);
                }

                X509EnhancedKeyUsageExtension ekuExt = ekuExts.Current;

                if (!ekuExt.Critical)
                {
                    return(false);
                }

                bool hasPurpose = false;

                foreach (Oid oid in ekuExt.EnhancedKeyUsages)
                {
                    if (oid.Value == Oids.TimeStampingPurpose)
                    {
                        hasPurpose = true;
                        break;
                    }
                }

                if (!hasPurpose)
                {
                    return(false);
                }

                if (ekuExts.MoveNext())
                {
                    return(false);
                }
            }

            try
            {
                signer.CheckSignature(new X509Certificate2Collection(tsaCertificate), true);
                return(true);
            }
            catch (CryptographicException)
            {
                return(false);
            }
        }