示例#1
0
        private static SctVerificationResult VerifySctSignatureOverBytes(this SignedCertificateTimestamp sct, Log logServer, byte[] toVerify)
        {
            var(oid, sigAlg) = GetKeyAlgorithm(logServer.KeyBytes);
            //var signer = sigAlg switch
            //{
            //    CtSignatureAlgorithm.Ecdsa => SignerUtilities.GetSigner(Constants.Sha256WithEcdsa),
            //    CtSignatureAlgorithm.Rsa => SignerUtilities.GetSigner(Constants.Sha256WithRsa),
            //    _ => throw new NotImplementedException($"Signature algothrim '{sigAlg}' not supported, with OID '{oid}'"),
            //};

            ISigner signer;

            if (sigAlg == CtSignatureAlgorithm.Ecdsa)
            {
                signer = SignerUtilities.GetSigner(Constants.Sha256WithEcdsa);
            }
            else if (sigAlg == CtSignatureAlgorithm.Rsa)
            {
                signer = SignerUtilities.GetSigner(Constants.Sha256WithRsa);
            }
            else
            {
                throw new NotImplementedException($"Signature algothrim '{sigAlg}' not supported, with OID '{oid}'");
            }

            var pubKey = PublicKeyFactory.CreateKey(logServer.KeyBytes);

            signer.Init(false, pubKey);
            signer.BlockUpdate(toVerify, 0, toVerify.Length);
            var isValid = signer.VerifySignature(sct.Signature.SignatureData);

            return(isValid
                ? SctVerificationResult.Valid(sct.TimestampUtc, logServer.LogId, logServer.Description)
                : SctVerificationResult.FailedVerification(sct.TimestampUtc, logServer.LogId, logServer.Description, "Invalid Signature"));
        }
示例#2
0
        internal static SctVerificationResult VerifySctOverPreCertificate(this SignedCertificateTimestamp sct, Log logServer, X509Certificate2 certificate, IssuerInformation issuerInfo)
        {
            var preCertificateTbs = CreateTbsForVerification(certificate, issuerInfo);
            var toVerify          = sct.SerialiseSignedSctDataForPreCertificate(preCertificateTbs.GetEncoded(), issuerInfo.KeyHash);

            return(sct.VerifySctSignatureOverBytes(logServer, toVerify));
        }
示例#3
0
        private static void SerialiseCommonFields(BinaryWriter bw, SignedCertificateTimestamp sct)
        {
            if (sct.SctVersion != SctVersion.V1)
            {
                throw new InvalidOperationException("Can only serialise SCT v1!");
            }

            bw.WriteLong((long)sct.SctVersion, Constants.VersionLength);
            bw.WriteLong(0, 1); // Certificate Timestamp
            bw.WriteLong(sct.TimestampMs, Constants.TimestampLength);
        }
示例#4
0
        private static byte[] SerialiseSignedSctData(this SignedCertificateTimestamp sct, X509Certificate2 certificate)
        {
            using var ms = new MemoryStream();
            using var bw = new BinaryWriter(ms);

            SerialiseCommonFields(bw, sct);

            bw.WriteLong(0, Constants.LogEntryTypeLength); // X509 Entry
            bw.WriteVariableLength(certificate.RawData, Constants.CertificateMaxLength);
            bw.WriteVariableLength(sct.Extensions, Constants.ExtensionsMaxLength);

            return(ms.ToArray());
        }
示例#5
0
        private static byte[] SerialiseSignedSctDataForPreCertificate(this SignedCertificateTimestamp sct, byte[] preCert, byte[] issuerKeyHash)
        {
            using var ms = new MemoryStream();
            using var bw = new BinaryWriter(ms);

            SerialiseCommonFields(bw, sct);

            bw.WriteLong(1, Constants.LogEntryTypeLength); // PerCert Entry
            bw.Write(issuerKeyHash);
            bw.WriteVariableLength(preCert, Constants.CertificateMaxLength);
            bw.WriteVariableLength(sct.Extensions, Constants.ExtensionsMaxLength);

            return(ms.ToArray());
        }
示例#6
0
        internal static SctVerificationResult VerifySignature(this SignedCertificateTimestamp sct, Log logServer, IList <X509Certificate2> chain)
        {
            if (logServer == null || sct == null || chain?.Any() != true || logServer.LogId != sct.LogIdBase64)
            {
                return(SctVerificationResult.FailedVerification(sct.TimestampUtc, logServer?.LogId, "Invalid verification arguments"));
            }

            var nowUtc = DateTime.UtcNow;

            if (sct.TimestampUtc > nowUtc)
            {
                return(SctVerificationResult.FutureTimestamp(sct.TimestampUtc, logServer.LogId));
            }

            if (logServer.ValidUntilUtc.HasValue && sct.TimestampUtc > logServer.ValidUntilUtc)
            {
                return(SctVerificationResult.LogServerUntrusted(sct.TimestampUtc, logServer.LogId));
            }

            try
            {
                var leafCert      = chain.First();
                var notPreCert    = !leafCert.IsPreCertificate();
                var noEmbeddedSct = !leafCert.HasEmbeddedSct();
                if (notPreCert && noEmbeddedSct)
                {
                    // When verifying final cert without embedded SCTs, we don't need the issuer but can verify directly
                    var toVerify = sct.SerialiseSignedSctData(leafCert);
                    return(sct.VerifySctSignatureOverBytes(logServer, toVerify));
                }

                if (chain.Count < 2)
                {
                    return(SctVerificationResult.FailedVerification(sct.TimestampUtc, logServer.LogId, "Chain with PreCertificate or Certificate must contain issuer"));
                }

                // PreCertificate or final certificate with embedded SCTs, we want the issuerInformation
                var issuerCert = chain[1];
                var isPreCertificateSigningCert = issuerCert.IsPreCertificateSigningCert();

                var issuerInformation = default(IssuerInformation);

                if (!isPreCertificateSigningCert)
                {
                    issuerInformation = issuerCert.IssuerInformation();
                }
                else if (chain.Count < 3)
                {
                    return(SctVerificationResult.FailedVerification(sct.TimestampUtc, logServer.LogId, "Chain with PreCertificate signed by PreCertificate Signing Cert must contain issuer"));
                }
                else
                {
                    issuerInformation = issuerCert.IssuerInformationFromPreCertificate(chain[2]);
                }

                return(VerifySctOverPreCertificate(sct, logServer, leafCert, issuerInformation));
            }
            catch (Exception ex)
            {
                return(SctVerificationResult.FailedWithException(sct.TimestampUtc, logServer.LogId, ex));
            }
        }
示例#7
0
        internal static List <SignedCertificateTimestamp> GetSignedCertificateTimestamps(this X509Certificate2 certificate)
        {
            // https://letsencrypt.org/2018/04/04/sct-encoding.html

            var result = new List <SignedCertificateTimestamp>();

#if DEBUG
            var sctExtension = certificate is MoqX509Certificate2 moqCert
                ? moqCert.Extensions
                               .OfType <X509Extension>()
                               .Where(i => i.Oid.Value.Equals(Constants.SctCertificateOid))
                               .FirstOrDefault()
                : certificate.GetExtension(Constants.SctCertificateOid);
#else
            var sctExtension = certificate.GetExtension(Constants.SctCertificateOid);
#endif
            if (sctExtension?.RawData?.Any() == true)
            {
                //var octets = Asn1OctetString.GetInstance(sctExtension.RawData).GetOctets();
                //var asn1 = Asn1Object.FromByteArray(sctExtension.RawData);
                //var octets = Asn1OctetString.GetInstance(asn1).GetOctets();
                var octets = sctExtension.RawData;
                // could be a nested OCTET string, check leading byte
                var derOctetString = octets[0] == 0x04
                    ? Asn1Object.FromByteArray(octets) as DerOctetString
                    : Asn1Object.FromByteArray(sctExtension.RawData) as DerOctetString;

                using (var inputStream = derOctetString.GetOctetStream())
                {
                    TlsUtilities.ReadUint16(inputStream);

                    while (inputStream.Length - inputStream.Position > 2)
                    {
                        var sctBytes = TlsUtilities.ReadOpaque16(inputStream);

                        using (var sctStream = new MemoryStream(sctBytes))
                        {
                            var version = (SctVersion)sctStream.ReadByte();
                            if (version != SctVersion.V1)
                            {
                                throw new NotSupportedException(UnknowError(nameof(SctVersion), version));
                            }

                            var keyId = new byte[Constants.KeyIdLength];
                            sctStream.Read(keyId, 0, keyId.Length);

                            var timestamp = sctStream.ReadLong(Constants.TimestampLength);

                            var extensions = sctStream.ReadVariableLength(Constants.ExtensionsMaxLength);

                            var hashAlgo = (CtHashAlgorithm)sctStream.ReadByte();
                            if (!Enum.IsDefined(typeof(CtHashAlgorithm), hashAlgo))
                            {
                                throw new NotSupportedException(UnknowError(nameof(CtHashAlgorithm), hashAlgo));
                            }

                            var signatureAlgo = (CtSignatureAlgorithm)sctStream.ReadByte();
                            if (!Enum.IsDefined(typeof(CtSignatureAlgorithm), signatureAlgo))
                            {
                                throw new NotSupportedException(UnknowError(nameof(CtSignatureAlgorithm), signatureAlgo));
                            }

                            var signature = sctStream.ReadVariableLength(Constants.SignatureMaxLength);

                            var digitallySigned = new DigitallySigned()
                            {
                                Hash          = hashAlgo,
                                Signature     = signatureAlgo,
                                SignatureData = signature
                            };

                            var sct = new SignedCertificateTimestamp()
                            {
                                SctVersion  = version,
                                LogId       = keyId,
                                TimestampMs = timestamp,
                                Extensions  = extensions,
                                Signature   = digitallySigned
                            };

                            result.Add(sct);
                        }
                    }
                }
            }

            return(result);
        }