private void validateCertificates(X509CertificateCollection certificates) { ServerContext context = (ServerContext)this.Context; AlertDescription description = AlertDescription.BadCertificate; SSCX.X509Certificate client = null; int[] certificateErrors = null; // note: certificate may be null is no certificate is sent // (e.g. optional mutual authentication) if (certificates.Count > 0) { X509Certificate leaf = certificates[0]; ArrayList errors = new ArrayList(); // SSL specific check - not all certificates can be // used to server-side SSL some rules applies after // all ;-) if (!checkCertificateUsage(leaf)) { // WinError.h CERT_E_PURPOSE 0x800B0106 errors.Add((int)-2146762490); } X509Chain verify; // was a chain supplied ? if so use it, if not if (certificates.Count > 1) { // if so use it (and don't build our own) X509CertificateCollection chain = new X509CertificateCollection(certificates); chain.Remove(leaf); verify = new X509Chain(chain); } else { // if not, then let's build our own (based on what's available in the stores) verify = new X509Chain(); } bool result = false; try { result = verify.Build(leaf); } catch (Exception) { result = false; } if (!result) { switch (verify.Status) { case X509ChainStatusFlags.InvalidBasicConstraints: // WinError.h TRUST_E_BASIC_CONSTRAINTS 0x80096019 errors.Add((int)-2146869223); break; case X509ChainStatusFlags.NotSignatureValid: // WinError.h TRUST_E_BAD_DIGEST 0x80096010 errors.Add((int)-2146869232); break; case X509ChainStatusFlags.NotTimeNested: // WinError.h CERT_E_VALIDITYPERIODNESTING 0x800B0102 errors.Add((int)-2146762494); break; case X509ChainStatusFlags.NotTimeValid: // WinError.h CERT_E_EXPIRED 0x800B0101 description = AlertDescription.CertificateExpired; errors.Add((int)-2146762495); break; case X509ChainStatusFlags.PartialChain: // WinError.h CERT_E_CHAINING 0x800B010A description = AlertDescription.UnknownCA; errors.Add((int)-2146762486); break; case X509ChainStatusFlags.UntrustedRoot: // WinError.h CERT_E_UNTRUSTEDROOT 0x800B0109 description = AlertDescription.UnknownCA; errors.Add((int)-2146762487); break; default: // unknown error description = AlertDescription.CertificateUnknown; errors.Add((int)verify.Status); break; } } client = new SSCX.X509Certificate(leaf.RawData); certificateErrors = (int[])errors.ToArray(typeof(int)); } else { certificateErrors = new int[0]; } SSCX.X509CertificateCollection certCollection = new SSCX.X509CertificateCollection(); foreach (X509Certificate certificate in certificates) { certCollection.Add(new SSCX.X509Certificate(certificate.RawData)); } if (!context.SslStream.RaiseClientCertificateValidation(client, certificateErrors)) { throw new TlsException( description, "Invalid certificate received from client."); } this.Context.ClientSettings.ClientCertificate = client; }
private void validateCertificates(X509CertificateCollection certificates) { ClientContext context = (ClientContext)this.Context; AlertDescription description = AlertDescription.BadCertificate; #if NET_2_0 if (context.SslStream.HaveRemoteValidation2Callback) { ValidationResult res = context.SslStream.RaiseServerCertificateValidation2(certificates); if (res.Trusted) { return; } long error = res.ErrorCode; switch (error) { case 0x800B0101: description = AlertDescription.CertificateExpired; break; case 0x800B010A: description = AlertDescription.UnknownCA; break; case 0x800B0109: description = AlertDescription.UnknownCA; break; default: description = AlertDescription.CertificateUnknown; break; } string err = String.Format("0x{0:x}", error); throw new TlsException(description, "Invalid certificate received from server. Error code: " + err); } #endif // the leaf is the web server certificate X509Certificate leaf = certificates [0]; X509Cert.X509Certificate cert = new X509Cert.X509Certificate(leaf.RawData); ArrayList errors = new ArrayList(); // SSL specific check - not all certificates can be // used to server-side SSL some rules applies after // all ;-) if (!checkCertificateUsage(leaf)) { // WinError.h CERT_E_PURPOSE 0x800B0106 errors.Add((int)-2146762490); } // SSL specific check - does the certificate match // the host ? if (!checkServerIdentity(leaf)) { // WinError.h CERT_E_CN_NO_MATCH 0x800B010F errors.Add((int)-2146762481); } // Note: building and verifying a chain can take much time // so we do it last (letting simple things fails first) // Note: In TLS the certificates MUST be in order (and // optionally include the root certificate) so we're not // building the chain using LoadCertificate (it's faster) // Note: IIS doesn't seem to send the whole certificate chain // but only the server certificate :-( it's assuming that you // already have this chain installed on your computer. duh! // http://groups.google.ca/groups?q=IIS+server+certificate+chain&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=85058s%24avd%241%40nnrp1.deja.com&rnum=3 // we must remove the leaf certificate from the chain X509CertificateCollection chain = new X509CertificateCollection(certificates); chain.Remove(leaf); X509Chain verify = new X509Chain(chain); bool result = false; try { result = verify.Build(leaf); } catch (Exception) { result = false; } if (!result) { switch (verify.Status) { case X509ChainStatusFlags.InvalidBasicConstraints: // WinError.h TRUST_E_BASIC_CONSTRAINTS 0x80096019 errors.Add((int)-2146869223); break; case X509ChainStatusFlags.NotSignatureValid: // WinError.h TRUST_E_BAD_DIGEST 0x80096010 errors.Add((int)-2146869232); break; case X509ChainStatusFlags.NotTimeNested: // WinError.h CERT_E_VALIDITYPERIODNESTING 0x800B0102 errors.Add((int)-2146762494); break; case X509ChainStatusFlags.NotTimeValid: // WinError.h CERT_E_EXPIRED 0x800B0101 description = AlertDescription.CertificateExpired; errors.Add((int)-2146762495); break; case X509ChainStatusFlags.PartialChain: // WinError.h CERT_E_CHAINING 0x800B010A description = AlertDescription.UnknownCA; errors.Add((int)-2146762486); break; case X509ChainStatusFlags.UntrustedRoot: // WinError.h CERT_E_UNTRUSTEDROOT 0x800B0109 description = AlertDescription.UnknownCA; errors.Add((int)-2146762487); break; default: // unknown error description = AlertDescription.CertificateUnknown; errors.Add((int)verify.Status); break; } } int[] certificateErrors = (int[])errors.ToArray(typeof(int)); if (!context.SslStream.RaiseServerCertificateValidation( cert, certificateErrors)) { throw new TlsException( description, "Invalid certificate received from server."); } }