| 153 _identity = PR_GetUniqueIdentity("Purple"); |
153 _identity = PR_GetUniqueIdentity("Purple"); |
| 154 _nss_methods = PR_GetDefaultIOMethods(); |
154 _nss_methods = PR_GetDefaultIOMethods(); |
| 155 } |
155 } |
| 156 |
156 |
| 157 static SECStatus |
157 static SECStatus |
| 158 ssl_auth_cert(void *arg, PRFileDesc *socket, PRBool checksig, |
158 ssl_auth_cert(void *arg, PRFileDesc *socket, PRBool checksig, PRBool is_server) |
| 159 PRBool is_server) |
159 { |
| 160 { |
160 /* We just skip cert verification here, and will verify the whole chain |
| |
161 * in ssl_nss_handshake_cb, after the handshake is complete. |
| |
162 * |
| |
163 * The problem is, purple_certificate_verify is asynchronous and |
| |
164 * ssl_auth_cert should return the result synchronously (it may ask the |
| |
165 * user, if an unknown certificate should be trusted or not). |
| |
166 * |
| |
167 * Ideally, SSL_AuthCertificateHook/ssl_auth_cert should decide |
| |
168 * immediately, if the certificate chain is already trusted and possibly |
| |
169 * SSL_BadCertHook to deal with unknown certificates. |
| |
170 * |
| |
171 * Current implementation may not be ideal, but is no less secure in |
| |
172 * terms of MITM attack. |
| |
173 */ |
| 161 return SECSuccess; |
174 return SECSuccess; |
| 162 |
175 } |
| 163 #if 0 |
|
| 164 CERTCertificate *cert; |
|
| 165 void *pinArg; |
|
| 166 SECStatus status; |
|
| 167 |
|
| 168 cert = SSL_PeerCertificate(socket); |
|
| 169 pinArg = SSL_RevealPinArg(socket); |
|
| 170 |
|
| 171 status = CERT_VerifyCertNow((CERTCertDBHandle *)arg, cert, checksig, |
|
| 172 certUsageSSLClient, pinArg); |
|
| 173 |
|
| 174 if (status != SECSuccess) { |
|
| 175 purple_debug_error("nss", "CERT_VerifyCertNow failed\n"); |
|
| 176 CERT_DestroyCertificate(cert); |
|
| 177 return status; |
|
| 178 } |
|
| 179 |
|
| 180 CERT_DestroyCertificate(cert); |
|
| 181 return SECSuccess; |
|
| 182 #endif |
|
| 183 } |
|
| 184 |
|
| 185 #if 0 |
|
| 186 static SECStatus |
|
| 187 ssl_bad_cert(void *arg, PRFileDesc *socket) |
|
| 188 { |
|
| 189 SECStatus status = SECFailure; |
|
| 190 PRErrorCode err; |
|
| 191 |
|
| 192 if (arg == NULL) |
|
| 193 return status; |
|
| 194 |
|
| 195 *(PRErrorCode *)arg = err = PORT_GetError(); |
|
| 196 |
|
| 197 switch (err) |
|
| 198 { |
|
| 199 case SEC_ERROR_INVALID_AVA: |
|
| 200 case SEC_ERROR_INVALID_TIME: |
|
| 201 case SEC_ERROR_BAD_SIGNATURE: |
|
| 202 case SEC_ERROR_EXPIRED_CERTIFICATE: |
|
| 203 case SEC_ERROR_UNKNOWN_ISSUER: |
|
| 204 case SEC_ERROR_UNTRUSTED_CERT: |
|
| 205 case SEC_ERROR_CERT_VALID: |
|
| 206 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: |
|
| 207 case SEC_ERROR_CRL_EXPIRED: |
|
| 208 case SEC_ERROR_CRL_BAD_SIGNATURE: |
|
| 209 case SEC_ERROR_EXTENSION_VALUE_INVALID: |
|
| 210 case SEC_ERROR_CA_CERT_INVALID: |
|
| 211 case SEC_ERROR_CERT_USAGES_INVALID: |
|
| 212 case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION: |
|
| 213 status = SECSuccess; |
|
| 214 break; |
|
| 215 |
|
| 216 default: |
|
| 217 status = SECFailure; |
|
| 218 break; |
|
| 219 } |
|
| 220 |
|
| 221 purple_debug_error("nss", "Bad certificate: %d\n", err); |
|
| 222 |
|
| 223 return status; |
|
| 224 } |
|
| 225 #endif |
|
| 226 |
176 |
| 227 static gboolean |
177 static gboolean |
| 228 ssl_nss_init(void) |
178 ssl_nss_init(void) |
| 229 { |
179 { |
| 230 return TRUE; |
180 return TRUE; |
| 360 gsc); |
310 gsc); |
| 361 |
311 |
| 362 purple_certificate_destroy_list(peers); |
312 purple_certificate_destroy_list(peers); |
| 363 } else { |
313 } else { |
| 364 /* Otherwise, just call the "connection complete" |
314 /* Otherwise, just call the "connection complete" |
| 365 callback */ |
315 * callback. The verification was already done with |
| |
316 * SSL_AuthCertificate, the default verifier |
| |
317 * (SSL_AuthCertificateHook was not called in ssl_nss_connect). |
| |
318 */ |
| 366 gsc->connect_cb(gsc->connect_cb_data, gsc, cond); |
319 gsc->connect_cb(gsc->connect_cb_data, gsc, cond); |
| 367 } |
320 } |
| 368 } |
321 } |
| 369 |
322 |
| 370 static gboolean |
323 static gboolean |
| 425 } |
378 } |
| 426 |
379 |
| 427 SSL_OptionSet(nss_data->in, SSL_SECURITY, PR_TRUE); |
380 SSL_OptionSet(nss_data->in, SSL_SECURITY, PR_TRUE); |
| 428 SSL_OptionSet(nss_data->in, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); |
381 SSL_OptionSet(nss_data->in, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); |
| 429 |
382 |
| 430 SSL_AuthCertificateHook(nss_data->in, |
383 /* If we have our internal verifier set up, use it. Otherwise, |
| 431 (SSLAuthCertificate)ssl_auth_cert, |
384 * use default. */ |
| 432 (void *)CERT_GetDefaultCertDB()); |
385 if (gsc->verifier != NULL) |
| 433 #if 0 |
386 SSL_AuthCertificateHook(nss_data->in, ssl_auth_cert, NULL); |
| 434 /* No point in hooking BadCert, since ssl_auth_cert always succeeds */ |
|
| 435 SSL_BadCertHook(nss_data->in, (SSLBadCertHandler)ssl_bad_cert, NULL); |
|
| 436 #endif |
|
| 437 |
387 |
| 438 if(gsc->host) |
388 if(gsc->host) |
| 439 SSL_SetURL(nss_data->in, gsc->host); |
389 SSL_SetURL(nss_data->in, gsc->host); |
| 440 |
390 |
| 441 #if 0 |
391 #if 0 |