NativeConnectionInfoPtr IceSSL::TransceiverI::getNativeConnectionInfo() const { NativeConnectionInfoPtr info = new NativeConnectionInfo(); IceInternal::fdToAddressAndPort(_stream->fd(), info->localAddress, info->localPort, info->remoteAddress, info->remotePort); if(_ssl) { for(int i = 0, count = SecTrustGetCertificateCount(_trust); i < count; ++i) { SecCertificateRef cert = SecTrustGetCertificateAtIndex(_trust, i); CFRetain(cert); CertificatePtr certificate = new Certificate(cert); info->nativeCerts.push_back(certificate); info->certs.push_back(certificate->encode()); } SSLCipherSuite cipher; SSLGetNegotiatedCipher(_ssl, &cipher); info->cipher = _engine->getCipherName(cipher); } info->adapterName = _adapterName; info->incoming = _incoming; return info; }
NativeConnectionInfoPtr IceSSL::TransceiverI::getNativeConnectionInfo() const { NativeConnectionInfoPtr info = new NativeConnectionInfo(); IceInternal::fdToAddressAndPort(_fd, info->localAddress, info->localPort, info->remoteAddress, info->remotePort); if(_ssl != 0) { // // On the client side, SSL_get_peer_cert_chain returns the entire chain of certs. // On the server side, the peer certificate must be obtained separately. // // Since we have no clear idea whether the connection is server or client side, // the peer certificate is obtained separately and compared against the first // certificate in the chain. If they are not the same, it is added to the chain. // X509* cert = SSL_get_peer_certificate(_ssl); STACK_OF(X509)* chain = SSL_get_peer_cert_chain(_ssl); if(cert != 0 && (chain == 0 || sk_X509_num(chain) == 0 || cert != sk_X509_value(chain, 0))) { CertificatePtr certificate = new Certificate(cert); info->nativeCerts.push_back(certificate); info->certs.push_back(certificate->encode()); } else { X509_free(cert); } if(chain != 0) { for(int i = 0; i < sk_X509_num(chain); ++i) { // // Duplicate the certificate since the stack comes straight from the SSL connection. // CertificatePtr certificate = new Certificate(X509_dup(sk_X509_value(chain, i))); info->nativeCerts.push_back(certificate); info->certs.push_back(certificate->encode()); } } info->cipher = SSL_get_cipher_name(_ssl); // Nothing needs to be free'd. } info->adapterName = _adapterName; info->incoming = _incoming; return info; }
void IceSSL::TransceiverI::fillConnectionInfo(const ConnectionInfoPtr& info, std::vector<CertificatePtr>& nativeCerts) const { IceInternal::fdToAddressAndPort(_stream->fd(), info->localAddress, info->localPort, info->remoteAddress, info->remotePort); if(_stream->fd() != INVALID_SOCKET) { info->rcvSize = IceInternal::getRecvBufferSize(_stream->fd()); info->sndSize = IceInternal::getSendBufferSize(_stream->fd()); } if(_ssl) { for(int i = 0, count = SecTrustGetCertificateCount(_trust); i < count; ++i) { SecCertificateRef cert = SecTrustGetCertificateAtIndex(_trust, i); CFRetain(cert); CertificatePtr certificate = ICE_MAKE_SHARED(Certificate, cert); nativeCerts.push_back(certificate); info->certs.push_back(certificate->encode()); } SSLCipherSuite cipher; SSLGetNegotiatedCipher(_ssl, &cipher); info->cipher = _engine->getCipherName(cipher); info->verified = _verified; } else { info->verified = false; } info->adapterName = _adapterName; info->incoming = _incoming; }
void IceSSL::TransceiverI::fillConnectionInfo(const ConnectionInfoPtr& info, vector<CertificatePtr>& nativeCerts) const { IceInternal::fdToAddressAndPort(_stream->fd(), info->localAddress, info->localPort, info->remoteAddress, info->remotePort); if(_stream->fd() != INVALID_SOCKET) { info->rcvSize = IceInternal::getRecvBufferSize(_stream->fd()); info->sndSize = IceInternal::getSendBufferSize(_stream->fd()); } info->verified = _verified; if(_sslInitialized) { CtxtHandle* ssl = const_cast<CtxtHandle*>(&_ssl); PCCERT_CONTEXT cert = 0; PCCERT_CHAIN_CONTEXT certChain = 0; SECURITY_STATUS err = QueryContextAttributes(ssl, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &cert); if(err == SEC_E_OK) { assert(cert); CERT_CHAIN_PARA chainP; memset(&chainP, 0, sizeof(chainP)); chainP.cbSize = sizeof(chainP); if(CertGetCertificateChain(_engine->chainEngine(), cert, 0, 0, &chainP, CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY, 0, &certChain)) { CERT_SIMPLE_CHAIN* simpleChain = certChain->rgpChain[0]; for(DWORD i = 0; i < simpleChain->cElement; ++i) { PCCERT_CONTEXT c = simpleChain->rgpElement[i]->pCertContext; PCERT_SIGNED_CONTENT_INFO cc; DWORD length = 0; if(!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_CERT, c->pbCertEncoded, c->cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, 0, &cc, &length)) { CertFreeCertificateChain(certChain); CertFreeCertificateContext(cert); throw SecurityException(__FILE__, __LINE__, "IceSSL: error decoding peer certificate chain:\n" + IceUtilInternal::lastErrorToString()); } CertificatePtr certificate = ICE_MAKE_SHARED(Certificate, cc); nativeCerts.push_back(certificate); info->certs.push_back(certificate->encode()); } CertFreeCertificateChain(certChain); } CertFreeCertificateContext(cert); } else if(err != SEC_E_NO_CREDENTIALS) { throw SecurityException(__FILE__, __LINE__, "IceSSL: error reading peer certificate:" + IceUtilInternal::lastErrorToString()); } SecPkgContext_ConnectionInfo connInfo; if(QueryContextAttributes(ssl, SECPKG_ATTR_CONNECTION_INFO, &connInfo) == SEC_E_OK) { info->cipher = _engine->getCipherName(connInfo.aiCipher); } else { throw SecurityException(__FILE__, __LINE__, "IceSSL: error reading cipher info:" + IceUtilInternal::lastErrorToString()); } } info->adapterName = _adapterName; info->incoming = _incoming; }
void IceSSL::SSLEngine::verifyPeerCertName(const string& address, const ConnectionInfoPtr& info) { // // For an outgoing connection, we compare the proxy address (if any) against // fields in the server's certificate (if any). // if(_checkCertName && !info->certs.empty() && !address.empty()) { const CertificatePtr cert = info->certs[0]; // // Extract the IP addresses and the DNS names from the subject // alternative names. // vector<pair<int, string> > subjectAltNames = cert->getSubjectAlternativeNames(); vector<string> ipAddresses; vector<string> dnsNames; for(vector<pair<int, string> >::const_iterator p = subjectAltNames.begin(); p != subjectAltNames.end(); ++p) { if(p->first == AltNAmeIP) { ipAddresses.push_back(IceUtilInternal::toLower(p->second)); } else if(p->first == AltNameDNS) { dnsNames.push_back(IceUtilInternal::toLower(p->second)); } } bool certNameOK = false; string addrLower = IceUtilInternal::toLower(address); bool isIpAddress = IceInternal::isIpAddress(address); // // If address is an IP address, compare it to the subject alternative names IP adddress // if(isIpAddress) { certNameOK = find(ipAddresses.begin(), ipAddresses.end(), addrLower) != ipAddresses.end(); } else { // // If subjectAlt is empty compare it ot the subject CN, othewise // compare it to the to the subject alt name dnsNames // if(dnsNames.empty()) { DistinguishedName d = cert->getSubjectDN(); string dn = IceUtilInternal::toLower(string(d)); string cn = "cn=" + addrLower; string::size_type pos = dn.find(cn); if(pos != string::npos) { // // Ensure we match the entire common name. // certNameOK = (pos + cn.size() == dn.size()) || (dn[pos + cn.size()] == ','); } } else { certNameOK = find(dnsNames.begin(), dnsNames.end(), addrLower) != dnsNames.end(); } } if(!certNameOK) { ostringstream ostr; ostr << "IceSSL: certificate validation failure: " << (isIpAddress ? "IP address mismatch" : "Hostname mismatch"); string msg = ostr.str(); if(_securityTraceLevel >= 1) { Trace out(_logger, _securityTraceCategory); out << msg; } if(_verifyPeer > 0) { throw SecurityException(__FILE__, __LINE__, msg); } } } }
void IceSSL::SSLEngine::verifyPeer(const string& address, const NativeConnectionInfoPtr& info, const string& desc) { const CertificateVerifierPtr verifier = getCertificateVerifier(); #if !defined(ICE_USE_SECURE_TRANSPORT_IOS) // // For an outgoing connection, we compare the proxy address (if any) against // fields in the server's certificate (if any). // if(!info->nativeCerts.empty() && !address.empty()) { const CertificatePtr cert = info->nativeCerts[0]; // // Extract the IP addresses and the DNS names from the subject // alternative names. // vector<pair<int, string> > subjectAltNames = cert->getSubjectAlternativeNames(); vector<string> ipAddresses; vector<string> dnsNames; for(vector<pair<int, string> >::const_iterator p = subjectAltNames.begin(); p != subjectAltNames.end(); ++p) { if(p->first == AltNAmeIP) { ipAddresses.push_back(IceUtilInternal::toLower(p->second)); } else if(p->first == AltNameDNS) { dnsNames.push_back(IceUtilInternal::toLower(p->second)); } } // // Compare the peer's address against the common name. // bool certNameOK = false; string dn; string addrLower = IceUtilInternal::toLower(address); { DistinguishedName d = cert->getSubjectDN(); dn = IceUtilInternal::toLower(string(d)); string cn = "cn=" + addrLower; string::size_type pos = dn.find(cn); if(pos != string::npos) { // // Ensure we match the entire common name. // certNameOK = (pos + cn.size() == dn.size()) || (dn[pos + cn.size()] == ','); } } // // Compare the peer's address against the dnsName and ipAddress // values in the subject alternative name. // if(!certNameOK) { certNameOK = find(ipAddresses.begin(), ipAddresses.end(), addrLower) != ipAddresses.end(); } if(!certNameOK) { certNameOK = find(dnsNames.begin(), dnsNames.end(), addrLower) != dnsNames.end(); } // // Log a message if the name comparison fails. If CheckCertName is defined, // we also raise an exception to abort the connection. Don't log a message if // CheckCertName is not defined and a verifier is present. // if(!certNameOK && (_checkCertName || (_securityTraceLevel >= 1 && !verifier))) { ostringstream ostr; ostr << "IceSSL: "; if(!_checkCertName) { ostr << "ignoring "; } ostr << "certificate validation failure:\npeer certificate does not have `" << address << "' as its commonName or in its subjectAltName extension"; if(!dn.empty()) { ostr << "\nSubject DN: " << dn; } if(!dnsNames.empty()) { ostr << "\nDNS names found in certificate: "; for(vector<string>::const_iterator p = dnsNames.begin(); p != dnsNames.end(); ++p) { if(p != dnsNames.begin()) { ostr << ", "; } ostr << *p; } } if(!ipAddresses.empty()) { ostr << "\nIP addresses found in certificate: "; for(vector<string>::const_iterator p = ipAddresses.begin(); p != ipAddresses.end(); ++p) { if(p != ipAddresses.begin()) { ostr << ", "; } ostr << *p; } } string msg = ostr.str(); if(_securityTraceLevel >= 1) { Trace out(_logger, _securityTraceCategory); out << msg; } if(_checkCertName) { SecurityException ex(__FILE__, __LINE__); ex.reason = msg; throw ex; } } } #endif if(_verifyDepthMax > 0 && static_cast<int>(info->certs.size()) > _verifyDepthMax) { ostringstream ostr; ostr << (info->incoming ? "incoming" : "outgoing") << " connection rejected:\n" << "length of peer's certificate chain (" << info->certs.size() << ") exceeds maximum of " << _verifyDepthMax; string msg = ostr.str(); if(_securityTraceLevel >= 1) { _logger->trace(_securityTraceCategory, msg + "\n" + desc); } SecurityException ex(__FILE__, __LINE__); ex.reason = msg; throw ex; } if(!_trustManager->verify(info, desc)) { string msg = string(info->incoming ? "incoming" : "outgoing") + " connection rejected by trust manager"; if(_securityTraceLevel >= 1) { _logger->trace(_securityTraceCategory, msg + "\n" + desc); } SecurityException ex(__FILE__, __LINE__); ex.reason = msg; throw ex; } if(verifier && !verifier->verify(info)) { string msg = string(info->incoming ? "incoming" : "outgoing") + " connection rejected by certificate verifier"; if(_securityTraceLevel >= 1) { _logger->trace(_securityTraceCategory, msg + "\n" + desc); } SecurityException ex(__FILE__, __LINE__); ex.reason = msg; throw ex; } }