private int ValidateCert(uint dwType, IntPtr pvArg, uint dwChainLen, IntPtr pCertChain, uint dwFlags) { //According to http://msdn.microsoft.com/en-us/library/ms940451.aspx: // //- dwChainLen is always 1 //- Windows CE performs the cert chain validation //- pvArg is the context data we passed into the SO_SSL_SET_VALIDATE_CERT_HOOK call so in our //- case is the host name // //So here we are responsible for validating the dates on the certificate and the CN if (!m_validateCertEnabled) { m_lastValidateCertError = SslValidateErrors.NotValidate; return(SSL_ERR_OKAY); } if (dwType != SSL_CERT_X59) { m_lastValidateCertError = SslValidateErrors.BadData; return(SSL_ERR_BAD_TYPE); } //When in debug mode let self-signed certificates through ... #if !DEBUG if ((dwFlags & SSL_CERT_FLAG_ISSUER_UNKNOWN) != 0) { m_lastValidateCertError = SslValidateErrors.InvalidIssuer; return(SSL_ERR_CERT_UNKNOWN); } #endif Debug.Assert(dwChainLen == 1); //Note about the note: an unmanaged long is 32 bits, unlike a managed long which is 64. I was missing //this fact when I wrote the comment. So the docs are accurate. //NOTE: The documentation says pCertChain is a pointer to a LPBLOB struct: // // {ulong size, byte* data} // //in reality the size is a 32 bit integer (not 64). int certSize = Marshal.ReadInt32(pCertChain); IntPtr pData = Marshal.ReadIntPtr(new IntPtr(pCertChain.ToInt32() + sizeof(int))); byte[] certData = new byte[certSize]; for (int i = 0; i < certSize; i++) { certData[i] = Marshal.ReadByte(pData, (int)i); } X509Certificate2 cert; try { cert = new X509Certificate2(certData); } catch (ArgumentException) { m_lastValidateCertError = SslValidateErrors.BadData; return(SSL_ERR_BAD_DATA); } catch (CryptographicException) { m_lastValidateCertError = SslValidateErrors.BadData; return(SSL_ERR_BAD_DATA); } //Validate the expiration date if (DateTime.Now > DateTime.Parse(cert.GetExpirationDateString(), CultureInfo.CurrentCulture)) { m_lastValidateCertError = SslValidateErrors.Expired; return(SSL_ERR_CERT_EXPIRED); } //Validate the effective date if (DateTime.Now < DateTime.Parse(cert.GetEffectiveDateString(), CultureInfo.CurrentCulture)) { m_lastValidateCertError = SslValidateErrors.NotEffectDate; return(SSL_ERR_FAILED); } string certName = cert.GetName(); Debug.WriteLine(certName); //Validate the CN string host = ReadAnsiString(pvArg); if (!certName.Contains("CN=" + host)) { m_lastValidateCertError = SslValidateErrors.OtherSite; return(SSL_ERR_FAILED); } m_lastValidateCertError = SslValidateErrors.Okay; return(SSL_ERR_OKAY); }
private int ValidateCert(uint dwType, IntPtr pvArg, uint dwChainLen, IntPtr pCertChain, uint dwFlags) { //According to http://msdn.microsoft.com/en-us/library/ms940451.aspx: // //- dwChainLen is always 1 //- Windows CE performs the cert chain validation //- pvArg is the context data we passed into the SO_SSL_SET_VALIDATE_CERT_HOOK call so in our //- case is the host name // //So here we are responsible for validating the dates on the certificate and the CN if (!m_validateCertEnabled) { m_lastValidateCertError = SslValidateErrors.NotValidate; return SSL_ERR_OKAY; } if (dwType != SSL_CERT_X59) { m_lastValidateCertError = SslValidateErrors.BadData; return SSL_ERR_BAD_TYPE; } //When in debug mode let self-signed certificates through ... #if !DEBUG if ((dwFlags & SSL_CERT_FLAG_ISSUER_UNKNOWN) != 0) { m_lastValidateCertError = SslValidateErrors.InvalidIssuer; return SSL_ERR_CERT_UNKNOWN; } #endif Debug.Assert(dwChainLen == 1); //Note about the note: an unmanaged long is 32 bits, unlike a managed long which is 64. I was missing //this fact when I wrote the comment. So the docs are accurate. //NOTE: The documentation says pCertChain is a pointer to a LPBLOB struct: // // {ulong size, byte* data} // //in reality the size is a 32 bit integer (not 64). int certSize = Marshal.ReadInt32(pCertChain); IntPtr pData = Marshal.ReadIntPtr(new IntPtr(pCertChain.ToInt32() + sizeof(int))); byte[] certData = new byte[certSize]; for (int i = 0; i < certSize; i++) certData[i] = Marshal.ReadByte(pData, (int)i); X509Certificate2 cert; try { cert = new X509Certificate2(certData); } catch (ArgumentException) { m_lastValidateCertError = SslValidateErrors.BadData; return SSL_ERR_BAD_DATA; } catch (CryptographicException) { m_lastValidateCertError = SslValidateErrors.BadData; return SSL_ERR_BAD_DATA; } //Validate the expiration date if (DateTime.Now > DateTime.Parse(cert.GetExpirationDateString(), CultureInfo.CurrentCulture)) { m_lastValidateCertError = SslValidateErrors.Expired; return SSL_ERR_CERT_EXPIRED; } //Validate the effective date if (DateTime.Now < DateTime.Parse(cert.GetEffectiveDateString(), CultureInfo.CurrentCulture)) { m_lastValidateCertError = SslValidateErrors.NotEffectDate; return SSL_ERR_FAILED; } string certName = cert.GetName(); Debug.WriteLine(certName); //Validate the CN string host = ReadAnsiString(pvArg); if (!certName.Contains("CN=" + host)) { m_lastValidateCertError = SslValidateErrors.OtherSite; return SSL_ERR_FAILED; } m_lastValidateCertError = SslValidateErrors.Okay; return SSL_ERR_OKAY; }