| 1130 | } |
| 1131 | |
| 1132 | void Handshake() override { |
| 1133 | Ssl_.Reset(SSL_new(SslCtx_)); |
| 1134 | if (THttpsOptions::EnableSslClientDebug) { |
| 1135 | SSL_set_info_callback(Ssl_.Get(), InfoCB); |
| 1136 | } |
| 1137 | |
| 1138 | BIO_up_ref(*Connection_); // SSL_set_bio consumes only one reference if rbio and wbio are the same |
| 1139 | SSL_set_bio(Ssl_.Get(), *Connection_, *Connection_); |
| 1140 | |
| 1141 | const TString hostname(Location_.Host); |
| 1142 | const int rev = SSL_set_tlsext_host_name(Ssl_.Get(), hostname.data()); |
| 1143 | if (Y_UNLIKELY(1 != rev)) { |
| 1144 | ythrow TSslException(TStringBuf("SSL_set_tlsext_host_name(client)"), Ssl_.Get(), rev); |
| 1145 | } |
| 1146 | |
| 1147 | TString cert, pvtKey; |
| 1148 | ParseUserInfo(Location_, cert, pvtKey); |
| 1149 | |
| 1150 | if (cert && (1 != SSL_use_certificate_file(Ssl_.Get(), cert.data(), SSL_FILETYPE_PEM))) { |
| 1151 | ythrow TSslException(TStringBuf("SSL_use_certificate_file(client)")); |
| 1152 | } |
| 1153 | |
| 1154 | if (pvtKey) { |
| 1155 | if (1 != SSL_use_PrivateKey_file(Ssl_.Get(), pvtKey.data(), SSL_FILETYPE_PEM)) { |
| 1156 | ythrow TSslException(TStringBuf("SSL_use_PrivateKey_file(client)")); |
| 1157 | } |
| 1158 | |
| 1159 | if (1 != SSL_check_private_key(Ssl_.Get())) { |
| 1160 | ythrow TSslException(TStringBuf("SSL_check_private_key(client)")); |
| 1161 | } |
| 1162 | } |
| 1163 | |
| 1164 | SSL_set_connect_state(Ssl_.Get()); |
| 1165 | |
| 1166 | // TODO restore session if reconnect |
| 1167 | const int rval = SSL_do_handshake(Ssl_.Get()); |
| 1168 | if (1 != rval) { |
| 1169 | if (rval == SSL_RVAL_TIMEOUT) { |
| 1170 | ythrow TSystemError(ECANCELED) << TStringBuf("canceled"); |
| 1171 | } else { |
| 1172 | ythrow TSslException(TStringBuf("BIO_do_handshake(client)"), Ssl_.Get(), rval); |
| 1173 | } |
| 1174 | } |
| 1175 | |
| 1176 | if (THttpsOptions::CheckCertificateHostname) { |
| 1177 | TX509Holder peerCert(SSL_get_peer_certificate(Ssl_.Get())); |
| 1178 | if (!peerCert) { |
| 1179 | ythrow TSslException(TStringBuf("SSL_get_peer_certificate(client)")); |
| 1180 | } |
| 1181 | |
| 1182 | if (!CheckCertHostname(peerCert.Get(), Location_.Host)) { |
| 1183 | ythrow TSslException(TStringBuf("CheckCertHostname(client)")); |
| 1184 | } |
| 1185 | } |
| 1186 | } |
| 1187 | |
| 1188 | private: |
| 1189 | const TParsedLocation Location_; |
no test coverage detected