/// <summary> /// Throws an exception if validation fails. /// </summary> /// <param name="certificate">The certificate to be checked.</param> /// <exception cref="ServiceResultException">If certificate cannot be accepted</exception> protected virtual void InternalValidate(IList <X509Certificate2> certificates) { lock (m_lock) { X509Certificate2 certificate = certificates[0]; // check for previously validated certificate. X509Certificate2 certificate2 = null; if (m_validatedCertificates.TryGetValue(certificate.Thumbprint, out certificate2)) { if (Utils.IsEqual(certificate2.RawData, certificate.RawData)) { return; } } CertificateIdentifier trustedCertificate = GetTrustedCertificate(certificate); // get the issuers (checks the revocation lists if using directory stores). List <CertificateIdentifier> issuers = new List <CertificateIdentifier>(); bool isIssuerTrusted = GetIssuers(certificates, issuers); // setup policy chain X509ChainPolicy policy = new X509ChainPolicy(); policy.RevocationFlag = X509RevocationFlag.EntireChain; policy.RevocationMode = X509RevocationMode.NoCheck; policy.VerificationFlags = X509VerificationFlags.NoFlag; foreach (CertificateIdentifier issuer in issuers) { if ((issuer.ValidationOptions & CertificateValidationOptions.SuppressRevocationStatusUnknown) != 0) { policy.VerificationFlags |= X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown; policy.VerificationFlags |= X509VerificationFlags.IgnoreCtlSignerRevocationUnknown; policy.VerificationFlags |= X509VerificationFlags.IgnoreEndRevocationUnknown; policy.VerificationFlags |= X509VerificationFlags.IgnoreRootRevocationUnknown; } // we did the revocation check in the GetIssuers call. No need here. policy.RevocationMode = X509RevocationMode.NoCheck; policy.ExtraStore.Add(issuer.Certificate); } // build chain. X509Chain chain = new X509Chain(); chain.ChainPolicy = policy; chain.Build(certificate); // check the chain results. CertificateIdentifier target = trustedCertificate; if (target == null) { target = new CertificateIdentifier(certificate); } for (int ii = 0; ii < chain.ChainElements.Count; ii++) { X509ChainElement element = chain.ChainElements[ii]; CertificateIdentifier issuer = null; if (ii < issuers.Count) { issuer = issuers[ii]; } // check for chain status errors. foreach (X509ChainStatus status in element.ChainElementStatus) { ServiceResult result = CheckChainStatus(status, target, issuer, (ii != 0)); if (ServiceResult.IsBad(result)) { throw new ServiceResultException(result); } } if (issuer != null) { target = issuer; } } // check if certificate is trusted. if (trustedCertificate == null && !isIssuerTrusted) { if (m_applicationCertificate == null || !Utils.IsEqual(m_applicationCertificate.RawData, certificate.RawData)) { throw ServiceResultException.Create( StatusCodes.BadCertificateUntrusted, "Certificate is not trusted.\r\nSubjectName: {0}\r\nIssuerName: {1}", certificate.SubjectName.Name, certificate.IssuerName.Name); } } } }
/// <summary> /// Parses a string representing a numeric range. /// </summary> /// <param name="textToParse">The text to parse, prior to checking it is within the allowed range</param> /// <param name="range">The parsed range.</param> /// <returns>The reason for any error.</returns> public static ServiceResult Validate(string textToParse, out NumericRange range) { range = NumericRange.Empty; if (String.IsNullOrEmpty(textToParse)) { return(ServiceResult.Good); } // check for multidimensional ranges. int index = textToParse.IndexOf(','); if (index >= 0) { int start = 0; List <NumericRange> subranges = new List <NumericRange>(); for (int ii = 0; ii < textToParse.Length; ii++) { char ch = textToParse[ii]; if (ch == ',' || ii == textToParse.Length - 1) { NumericRange subrange = new NumericRange(); string subtext = (ch == ',') ? textToParse.Substring(start, ii - start) : textToParse.Substring(start); ServiceResult result = Validate(subtext, out subrange); if (ServiceResult.IsBad(result)) { return(result); } subranges.Add(subrange); start = ii + 1; } } // must have at least two entries. if (subranges.Count < 2) { return(StatusCodes.BadIndexRangeInvalid); } range.m_begin = subranges[0].Begin; range.m_end = subranges[0].End; range.m_subranges = subranges.ToArray(); return(ServiceResult.Good); } try { index = textToParse.IndexOf(':'); if (index != -1) { range.Begin = Convert.ToInt32(textToParse.Substring(0, index), CultureInfo.InvariantCulture); range.End = Convert.ToInt32(textToParse.Substring(index + 1), CultureInfo.InvariantCulture); if (range.End < 0) { return(ServiceResult.Create( StatusCodes.BadIndexRangeInvalid, "NumericRange does not have a valid end index ({0}).", range.End)); } if (range.Begin >= range.End) { return(ServiceResult.Create( StatusCodes.BadIndexRangeInvalid, "NumericRange does not have a start index that is less than the end index ({0}).", range)); } } else { range.Begin = Convert.ToInt32(textToParse, CultureInfo.InvariantCulture); range.End = -1; } if (range.Begin < 0) { return(ServiceResult.Create( StatusCodes.BadIndexRangeInvalid, "NumericRange does not have a valid start index ({0}).", range.Begin)); } } catch (Exception e) { return(ServiceResult.Create( e, StatusCodes.BadIndexRangeInvalid, "NumericRange cannot be parsed ({0}).", textToParse)); } return(ServiceResult.Good); }