OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include <vector> | |
12 | |
13 #if HAVE_CONFIG_H | |
14 #include "config.h" | |
15 #endif // HAVE_CONFIG_H | |
16 | |
17 #if HAVE_NSS_SSL_H | |
18 | |
19 #include "webrtc/base/nssstreamadapter.h" | |
20 | |
21 #include "keyhi.h" | |
22 #include "nspr.h" | |
23 #include "nss.h" | |
24 #include "pk11pub.h" | |
25 #include "secerr.h" | |
26 | |
27 #ifdef NSS_SSL_RELATIVE_PATH | |
28 #include "ssl.h" | |
29 #include "sslerr.h" | |
30 #include "sslproto.h" | |
31 #else | |
32 #include "net/third_party/nss/ssl/ssl.h" | |
33 #include "net/third_party/nss/ssl/sslerr.h" | |
34 #include "net/third_party/nss/ssl/sslproto.h" | |
35 #endif | |
36 | |
37 #include "webrtc/base/nssidentity.h" | |
38 #include "webrtc/base/safe_conversions.h" | |
39 #include "webrtc/base/thread.h" | |
40 | |
41 namespace rtc { | |
42 | |
43 PRDescIdentity NSSStreamAdapter::nspr_layer_identity = PR_INVALID_IO_LAYER; | |
44 | |
45 #define UNIMPLEMENTED \ | |
46 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); \ | |
47 LOG(LS_ERROR) \ | |
48 << "Call to unimplemented function "<< __FUNCTION__; ASSERT(false) | |
49 | |
50 #ifdef SRTP_AES128_CM_HMAC_SHA1_80 | |
51 #define HAVE_DTLS_SRTP | |
52 #endif | |
53 | |
54 #ifdef HAVE_DTLS_SRTP | |
55 // SRTP cipher suite table | |
56 struct SrtpCipherMapEntry { | |
57 const char* external_name; | |
58 PRUint16 cipher_id; | |
59 }; | |
60 | |
61 // This isn't elegant, but it's better than an external reference | |
62 static const SrtpCipherMapEntry kSrtpCipherMap[] = { | |
63 {"AES_CM_128_HMAC_SHA1_80", SRTP_AES128_CM_HMAC_SHA1_80 }, | |
64 {"AES_CM_128_HMAC_SHA1_32", SRTP_AES128_CM_HMAC_SHA1_32 }, | |
65 {NULL, 0} | |
66 }; | |
67 #endif | |
68 | |
69 // Ciphers to enable to get ECDHE encryption with endpoints that support it. | |
70 static const uint32_t kEnabledCiphers[] = { | |
71 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, | |
72 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | |
73 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, | |
74 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}; | |
75 | |
76 // Default cipher used between NSS stream adapters. | |
77 // This needs to be updated when the default of the SSL library changes. | |
78 static const char kDefaultSslCipher10[] = | |
79 "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"; | |
80 static const char kDefaultSslCipher12[] = | |
81 "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"; | |
82 static const char kDefaultSslEcCipher10[] = | |
83 "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"; | |
84 static const char kDefaultSslEcCipher12[] = | |
85 "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"; | |
86 | |
87 // Implementation of NSPR methods | |
88 static PRStatus StreamClose(PRFileDesc *socket) { | |
89 ASSERT(!socket->lower); | |
90 socket->dtor(socket); | |
91 return PR_SUCCESS; | |
92 } | |
93 | |
94 static PRInt32 StreamRead(PRFileDesc *socket, void *buf, PRInt32 length) { | |
95 StreamInterface *stream = reinterpret_cast<StreamInterface *>(socket->secret); | |
96 size_t read; | |
97 int error; | |
98 StreamResult result = stream->Read(buf, length, &read, &error); | |
99 if (result == SR_SUCCESS) { | |
100 return checked_cast<PRInt32>(read); | |
101 } | |
102 | |
103 if (result == SR_EOS) { | |
104 return 0; | |
105 } | |
106 | |
107 if (result == SR_BLOCK) { | |
108 PR_SetError(PR_WOULD_BLOCK_ERROR, 0); | |
109 return -1; | |
110 } | |
111 | |
112 PR_SetError(PR_UNKNOWN_ERROR, error); | |
113 return -1; | |
114 } | |
115 | |
116 static PRInt32 StreamWrite(PRFileDesc *socket, const void *buf, | |
117 PRInt32 length) { | |
118 StreamInterface *stream = reinterpret_cast<StreamInterface *>(socket->secret); | |
119 size_t written; | |
120 int error; | |
121 StreamResult result = stream->Write(buf, length, &written, &error); | |
122 if (result == SR_SUCCESS) { | |
123 return checked_cast<PRInt32>(written); | |
124 } | |
125 | |
126 if (result == SR_BLOCK) { | |
127 LOG(LS_INFO) << | |
128 "NSSStreamAdapter: write to underlying transport would block"; | |
129 PR_SetError(PR_WOULD_BLOCK_ERROR, 0); | |
130 return -1; | |
131 } | |
132 | |
133 LOG(LS_ERROR) << "Write error"; | |
134 PR_SetError(PR_UNKNOWN_ERROR, error); | |
135 return -1; | |
136 } | |
137 | |
138 static PRInt32 StreamAvailable(PRFileDesc *socket) { | |
139 UNIMPLEMENTED; | |
140 return -1; | |
141 } | |
142 | |
143 PRInt64 StreamAvailable64(PRFileDesc *socket) { | |
144 UNIMPLEMENTED; | |
145 return -1; | |
146 } | |
147 | |
148 static PRStatus StreamSync(PRFileDesc *socket) { | |
149 UNIMPLEMENTED; | |
150 return PR_FAILURE; | |
151 } | |
152 | |
153 static PROffset32 StreamSeek(PRFileDesc *socket, PROffset32 offset, | |
154 PRSeekWhence how) { | |
155 UNIMPLEMENTED; | |
156 return -1; | |
157 } | |
158 | |
159 static PROffset64 StreamSeek64(PRFileDesc *socket, PROffset64 offset, | |
160 PRSeekWhence how) { | |
161 UNIMPLEMENTED; | |
162 return -1; | |
163 } | |
164 | |
165 static PRStatus StreamFileInfo(PRFileDesc *socket, PRFileInfo *info) { | |
166 UNIMPLEMENTED; | |
167 return PR_FAILURE; | |
168 } | |
169 | |
170 static PRStatus StreamFileInfo64(PRFileDesc *socket, PRFileInfo64 *info) { | |
171 UNIMPLEMENTED; | |
172 return PR_FAILURE; | |
173 } | |
174 | |
175 static PRInt32 StreamWritev(PRFileDesc *socket, const PRIOVec *iov, | |
176 PRInt32 iov_size, PRIntervalTime timeout) { | |
177 UNIMPLEMENTED; | |
178 return -1; | |
179 } | |
180 | |
181 static PRStatus StreamConnect(PRFileDesc *socket, const PRNetAddr *addr, | |
182 PRIntervalTime timeout) { | |
183 UNIMPLEMENTED; | |
184 return PR_FAILURE; | |
185 } | |
186 | |
187 static PRFileDesc *StreamAccept(PRFileDesc *sd, PRNetAddr *addr, | |
188 PRIntervalTime timeout) { | |
189 UNIMPLEMENTED; | |
190 return NULL; | |
191 } | |
192 | |
193 static PRStatus StreamBind(PRFileDesc *socket, const PRNetAddr *addr) { | |
194 UNIMPLEMENTED; | |
195 return PR_FAILURE; | |
196 } | |
197 | |
198 static PRStatus StreamListen(PRFileDesc *socket, PRIntn depth) { | |
199 UNIMPLEMENTED; | |
200 return PR_FAILURE; | |
201 } | |
202 | |
203 static PRStatus StreamShutdown(PRFileDesc *socket, PRIntn how) { | |
204 UNIMPLEMENTED; | |
205 return PR_FAILURE; | |
206 } | |
207 | |
208 // Note: this is always nonblocking and ignores the timeout. | |
209 // TODO(ekr@rtfm.com): In future verify that the socket is | |
210 // actually in non-blocking mode. | |
211 // This function does not support peek. | |
212 static PRInt32 StreamRecv(PRFileDesc *socket, void *buf, PRInt32 amount, | |
213 PRIntn flags, PRIntervalTime to) { | |
214 ASSERT(flags == 0); | |
215 | |
216 if (flags != 0) { | |
217 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | |
218 return -1; | |
219 } | |
220 | |
221 return StreamRead(socket, buf, amount); | |
222 } | |
223 | |
224 // Note: this is always nonblocking and assumes a zero timeout. | |
225 // This function does not support peek. | |
226 static PRInt32 StreamSend(PRFileDesc *socket, const void *buf, | |
227 PRInt32 amount, PRIntn flags, | |
228 PRIntervalTime to) { | |
229 ASSERT(flags == 0); | |
230 | |
231 return StreamWrite(socket, buf, amount); | |
232 } | |
233 | |
234 static PRInt32 StreamRecvfrom(PRFileDesc *socket, void *buf, | |
235 PRInt32 amount, PRIntn flags, | |
236 PRNetAddr *addr, PRIntervalTime to) { | |
237 UNIMPLEMENTED; | |
238 return -1; | |
239 } | |
240 | |
241 static PRInt32 StreamSendto(PRFileDesc *socket, const void *buf, | |
242 PRInt32 amount, PRIntn flags, | |
243 const PRNetAddr *addr, PRIntervalTime to) { | |
244 UNIMPLEMENTED; | |
245 return -1; | |
246 } | |
247 | |
248 static PRInt16 StreamPoll(PRFileDesc *socket, PRInt16 in_flags, | |
249 PRInt16 *out_flags) { | |
250 UNIMPLEMENTED; | |
251 return -1; | |
252 } | |
253 | |
254 static PRInt32 StreamAcceptRead(PRFileDesc *sd, PRFileDesc **nd, | |
255 PRNetAddr **raddr, | |
256 void *buf, PRInt32 amount, PRIntervalTime t) { | |
257 UNIMPLEMENTED; | |
258 return -1; | |
259 } | |
260 | |
261 static PRInt32 StreamTransmitFile(PRFileDesc *sd, PRFileDesc *socket, | |
262 const void *headers, PRInt32 hlen, | |
263 PRTransmitFileFlags flags, PRIntervalTime t) { | |
264 UNIMPLEMENTED; | |
265 return -1; | |
266 } | |
267 | |
268 static PRStatus StreamGetPeerName(PRFileDesc *socket, PRNetAddr *addr) { | |
269 // TODO(ekr@rtfm.com): Modify to return unique names for each channel | |
270 // somehow, as opposed to always the same static address. The current | |
271 // implementation messes up the session cache, which is why it's off | |
272 // elsewhere | |
273 addr->inet.family = PR_AF_INET; | |
274 addr->inet.port = 0; | |
275 addr->inet.ip = 0; | |
276 | |
277 return PR_SUCCESS; | |
278 } | |
279 | |
280 static PRStatus StreamGetSockName(PRFileDesc *socket, PRNetAddr *addr) { | |
281 UNIMPLEMENTED; | |
282 return PR_FAILURE; | |
283 } | |
284 | |
285 static PRStatus StreamGetSockOption(PRFileDesc *socket, PRSocketOptionData *opt)
{ | |
286 switch (opt->option) { | |
287 case PR_SockOpt_Nonblocking: | |
288 opt->value.non_blocking = PR_TRUE; | |
289 return PR_SUCCESS; | |
290 default: | |
291 UNIMPLEMENTED; | |
292 break; | |
293 } | |
294 | |
295 return PR_FAILURE; | |
296 } | |
297 | |
298 // Imitate setting socket options. These are mostly noops. | |
299 static PRStatus StreamSetSockOption(PRFileDesc *socket, | |
300 const PRSocketOptionData *opt) { | |
301 switch (opt->option) { | |
302 case PR_SockOpt_Nonblocking: | |
303 return PR_SUCCESS; | |
304 case PR_SockOpt_NoDelay: | |
305 return PR_SUCCESS; | |
306 default: | |
307 UNIMPLEMENTED; | |
308 break; | |
309 } | |
310 | |
311 return PR_FAILURE; | |
312 } | |
313 | |
314 static PRInt32 StreamSendfile(PRFileDesc *out, PRSendFileData *in, | |
315 PRTransmitFileFlags flags, PRIntervalTime to) { | |
316 UNIMPLEMENTED; | |
317 return -1; | |
318 } | |
319 | |
320 static PRStatus StreamConnectContinue(PRFileDesc *socket, PRInt16 flags) { | |
321 UNIMPLEMENTED; | |
322 return PR_FAILURE; | |
323 } | |
324 | |
325 static PRIntn StreamReserved(PRFileDesc *socket) { | |
326 UNIMPLEMENTED; | |
327 return -1; | |
328 } | |
329 | |
330 static const struct PRIOMethods nss_methods = { | |
331 PR_DESC_LAYERED, | |
332 StreamClose, | |
333 StreamRead, | |
334 StreamWrite, | |
335 StreamAvailable, | |
336 StreamAvailable64, | |
337 StreamSync, | |
338 StreamSeek, | |
339 StreamSeek64, | |
340 StreamFileInfo, | |
341 StreamFileInfo64, | |
342 StreamWritev, | |
343 StreamConnect, | |
344 StreamAccept, | |
345 StreamBind, | |
346 StreamListen, | |
347 StreamShutdown, | |
348 StreamRecv, | |
349 StreamSend, | |
350 StreamRecvfrom, | |
351 StreamSendto, | |
352 StreamPoll, | |
353 StreamAcceptRead, | |
354 StreamTransmitFile, | |
355 StreamGetSockName, | |
356 StreamGetPeerName, | |
357 StreamReserved, | |
358 StreamReserved, | |
359 StreamGetSockOption, | |
360 StreamSetSockOption, | |
361 StreamSendfile, | |
362 StreamConnectContinue, | |
363 StreamReserved, | |
364 StreamReserved, | |
365 StreamReserved, | |
366 StreamReserved | |
367 }; | |
368 | |
369 NSSStreamAdapter::NSSStreamAdapter(StreamInterface *stream) | |
370 : SSLStreamAdapterHelper(stream), | |
371 ssl_fd_(NULL), | |
372 cert_ok_(false) { | |
373 } | |
374 | |
375 bool NSSStreamAdapter::Init() { | |
376 if (nspr_layer_identity == PR_INVALID_IO_LAYER) { | |
377 nspr_layer_identity = PR_GetUniqueIdentity("nssstreamadapter"); | |
378 } | |
379 PRFileDesc *pr_fd = PR_CreateIOLayerStub(nspr_layer_identity, &nss_methods); | |
380 if (!pr_fd) | |
381 return false; | |
382 pr_fd->secret = reinterpret_cast<PRFilePrivate *>(stream()); | |
383 | |
384 PRFileDesc *ssl_fd; | |
385 if (ssl_mode_ == SSL_MODE_DTLS) { | |
386 ssl_fd = DTLS_ImportFD(NULL, pr_fd); | |
387 } else { | |
388 ssl_fd = SSL_ImportFD(NULL, pr_fd); | |
389 } | |
390 ASSERT(ssl_fd != NULL); // This should never happen | |
391 if (!ssl_fd) { | |
392 PR_Close(pr_fd); | |
393 return false; | |
394 } | |
395 | |
396 SECStatus rv; | |
397 // Turn on security. | |
398 rv = SSL_OptionSet(ssl_fd, SSL_SECURITY, PR_TRUE); | |
399 if (rv != SECSuccess) { | |
400 LOG(LS_ERROR) << "Error enabling security on SSL Socket"; | |
401 return false; | |
402 } | |
403 | |
404 // Disable SSLv2. | |
405 rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_SSL2, PR_FALSE); | |
406 if (rv != SECSuccess) { | |
407 LOG(LS_ERROR) << "Error disabling SSL2"; | |
408 return false; | |
409 } | |
410 | |
411 // Disable caching. | |
412 // TODO(ekr@rtfm.com): restore this when I have the caching | |
413 // identity set. | |
414 rv = SSL_OptionSet(ssl_fd, SSL_NO_CACHE, PR_TRUE); | |
415 if (rv != SECSuccess) { | |
416 LOG(LS_ERROR) << "Error disabling cache"; | |
417 return false; | |
418 } | |
419 | |
420 // Disable session tickets. | |
421 rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_SESSION_TICKETS, PR_FALSE); | |
422 if (rv != SECSuccess) { | |
423 LOG(LS_ERROR) << "Error enabling tickets"; | |
424 return false; | |
425 } | |
426 | |
427 // Disable renegotiation. | |
428 rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_RENEGOTIATION, | |
429 SSL_RENEGOTIATE_NEVER); | |
430 if (rv != SECSuccess) { | |
431 LOG(LS_ERROR) << "Error disabling renegotiation"; | |
432 return false; | |
433 } | |
434 | |
435 // Disable false start. | |
436 rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_FALSE_START, PR_FALSE); | |
437 if (rv != SECSuccess) { | |
438 LOG(LS_ERROR) << "Error disabling false start"; | |
439 return false; | |
440 } | |
441 | |
442 // Disable reusing of ECDHE keys. By default NSS, when in server mode, uses | |
443 // the same key for multiple connections, so disable this behaviour to get | |
444 // ephemeral keys. | |
445 rv = SSL_OptionSet(ssl_fd, SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE); | |
446 if (rv != SECSuccess) { | |
447 LOG(LS_ERROR) << "Error disabling ECDHE key reuse"; | |
448 return false; | |
449 } | |
450 | |
451 ssl_fd_ = ssl_fd; | |
452 | |
453 return true; | |
454 } | |
455 | |
456 NSSStreamAdapter::~NSSStreamAdapter() { | |
457 if (ssl_fd_) | |
458 PR_Close(ssl_fd_); | |
459 }; | |
460 | |
461 | |
462 int NSSStreamAdapter::BeginSSL() { | |
463 SECStatus rv; | |
464 | |
465 if (!Init()) { | |
466 Error("Init", -1, false); | |
467 return -1; | |
468 } | |
469 | |
470 ASSERT(state_ == SSL_CONNECTING); | |
471 // The underlying stream has been opened. If we are in peer-to-peer mode | |
472 // then a peer certificate must have been specified by now. | |
473 ASSERT(!ssl_server_name_.empty() || | |
474 peer_certificate_.get() != NULL || | |
475 !peer_certificate_digest_algorithm_.empty()); | |
476 LOG(LS_INFO) << "BeginSSL: " | |
477 << (!ssl_server_name_.empty() ? ssl_server_name_ : | |
478 "with peer"); | |
479 | |
480 if (role_ == SSL_CLIENT) { | |
481 LOG(LS_INFO) << "BeginSSL: as client"; | |
482 | |
483 rv = SSL_GetClientAuthDataHook(ssl_fd_, GetClientAuthDataHook, | |
484 this); | |
485 if (rv != SECSuccess) { | |
486 Error("BeginSSL", -1, false); | |
487 return -1; | |
488 } | |
489 } else { | |
490 LOG(LS_INFO) << "BeginSSL: as server"; | |
491 NSSIdentity *identity; | |
492 | |
493 if (identity_.get()) { | |
494 identity = static_cast<NSSIdentity *>(identity_.get()); | |
495 } else { | |
496 LOG(LS_ERROR) << "Can't be an SSL server without an identity"; | |
497 Error("BeginSSL", -1, false); | |
498 return -1; | |
499 } | |
500 rv = SSL_ConfigSecureServer(ssl_fd_, identity->certificate().certificate(), | |
501 identity->keypair()->privkey(), | |
502 identity->keypair()->ssl_kea_type()); | |
503 if (rv != SECSuccess) { | |
504 Error("BeginSSL", -1, false); | |
505 return -1; | |
506 } | |
507 | |
508 // Insist on a certificate from the client | |
509 rv = SSL_OptionSet(ssl_fd_, SSL_REQUEST_CERTIFICATE, PR_TRUE); | |
510 if (rv != SECSuccess) { | |
511 Error("BeginSSL", -1, false); | |
512 return -1; | |
513 } | |
514 | |
515 // TODO(juberti): Check for client_auth_enabled() | |
516 | |
517 rv = SSL_OptionSet(ssl_fd_, SSL_REQUIRE_CERTIFICATE, PR_TRUE); | |
518 if (rv != SECSuccess) { | |
519 Error("BeginSSL", -1, false); | |
520 return -1; | |
521 } | |
522 } | |
523 | |
524 // Set the version range. | |
525 SSLVersionRange vrange; | |
526 if (ssl_mode_ == SSL_MODE_DTLS) { | |
527 vrange.min = SSL_LIBRARY_VERSION_TLS_1_1; | |
528 switch (ssl_max_version_) { | |
529 case SSL_PROTOCOL_DTLS_10: | |
530 vrange.max = SSL_LIBRARY_VERSION_TLS_1_1; | |
531 break; | |
532 case SSL_PROTOCOL_DTLS_12: | |
533 default: | |
534 vrange.max = SSL_LIBRARY_VERSION_TLS_1_2; | |
535 break; | |
536 } | |
537 } else { | |
538 // SSL_MODE_TLS | |
539 vrange.min = SSL_LIBRARY_VERSION_TLS_1_0; | |
540 switch (ssl_max_version_) { | |
541 case SSL_PROTOCOL_TLS_10: | |
542 vrange.max = SSL_LIBRARY_VERSION_TLS_1_0; | |
543 break; | |
544 case SSL_PROTOCOL_TLS_11: | |
545 vrange.max = SSL_LIBRARY_VERSION_TLS_1_1; | |
546 break; | |
547 case SSL_PROTOCOL_TLS_12: | |
548 default: | |
549 vrange.max = SSL_LIBRARY_VERSION_TLS_1_2; | |
550 break; | |
551 } | |
552 } | |
553 | |
554 rv = SSL_VersionRangeSet(ssl_fd_, &vrange); | |
555 if (rv != SECSuccess) { | |
556 Error("BeginSSL", -1, false); | |
557 return -1; | |
558 } | |
559 | |
560 // SRTP | |
561 #ifdef HAVE_DTLS_SRTP | |
562 if (!srtp_ciphers_.empty()) { | |
563 rv = SSL_SetSRTPCiphers( | |
564 ssl_fd_, &srtp_ciphers_[0], | |
565 checked_cast<unsigned int>(srtp_ciphers_.size())); | |
566 if (rv != SECSuccess) { | |
567 Error("BeginSSL", -1, false); | |
568 return -1; | |
569 } | |
570 } | |
571 #endif | |
572 | |
573 // Enable additional ciphers. | |
574 for (size_t i = 0; i < ARRAY_SIZE(kEnabledCiphers); i++) { | |
575 rv = SSL_CipherPrefSet(ssl_fd_, kEnabledCiphers[i], PR_TRUE); | |
576 if (rv != SECSuccess) { | |
577 Error("BeginSSL", -1, false); | |
578 return -1; | |
579 } | |
580 } | |
581 | |
582 // Certificate validation | |
583 rv = SSL_AuthCertificateHook(ssl_fd_, AuthCertificateHook, this); | |
584 if (rv != SECSuccess) { | |
585 Error("BeginSSL", -1, false); | |
586 return -1; | |
587 } | |
588 | |
589 // Now start the handshake | |
590 rv = SSL_ResetHandshake(ssl_fd_, role_ == SSL_SERVER ? PR_TRUE : PR_FALSE); | |
591 if (rv != SECSuccess) { | |
592 Error("BeginSSL", -1, false); | |
593 return -1; | |
594 } | |
595 | |
596 return ContinueSSL(); | |
597 } | |
598 | |
599 int NSSStreamAdapter::ContinueSSL() { | |
600 LOG(LS_INFO) << "ContinueSSL"; | |
601 ASSERT(state_ == SSL_CONNECTING); | |
602 | |
603 // Clear the DTLS timer | |
604 Thread::Current()->Clear(this, MSG_DTLS_TIMEOUT); | |
605 | |
606 SECStatus rv = SSL_ForceHandshake(ssl_fd_); | |
607 | |
608 if (rv == SECSuccess) { | |
609 LOG(LS_INFO) << "Handshake complete"; | |
610 | |
611 ASSERT(cert_ok_); | |
612 if (!cert_ok_) { | |
613 Error("ContinueSSL", -1, true); | |
614 return -1; | |
615 } | |
616 | |
617 state_ = SSL_CONNECTED; | |
618 StreamAdapterInterface::OnEvent(stream(), SE_OPEN|SE_READ|SE_WRITE, 0); | |
619 return 0; | |
620 } | |
621 | |
622 PRInt32 err = PR_GetError(); | |
623 switch (err) { | |
624 case SSL_ERROR_RX_MALFORMED_HANDSHAKE: | |
625 if (ssl_mode_ != SSL_MODE_DTLS) { | |
626 Error("ContinueSSL", -1, true); | |
627 return -1; | |
628 } else { | |
629 LOG(LS_INFO) << "Malformed DTLS message. Ignoring."; | |
630 FALLTHROUGH(); // Fall through | |
631 } | |
632 case PR_WOULD_BLOCK_ERROR: | |
633 LOG(LS_INFO) << "Would have blocked"; | |
634 if (ssl_mode_ == SSL_MODE_DTLS) { | |
635 PRIntervalTime timeout; | |
636 | |
637 SECStatus rv = DTLS_GetHandshakeTimeout(ssl_fd_, &timeout); | |
638 if (rv == SECSuccess) { | |
639 LOG(LS_INFO) << "Timeout is " << timeout << " ms"; | |
640 Thread::Current()->PostDelayed(PR_IntervalToMilliseconds(timeout), | |
641 this, MSG_DTLS_TIMEOUT, 0); | |
642 } | |
643 } | |
644 | |
645 return 0; | |
646 default: | |
647 LOG(LS_INFO) << "Error " << err; | |
648 break; | |
649 } | |
650 | |
651 Error("ContinueSSL", -1, true); | |
652 return -1; | |
653 } | |
654 | |
655 void NSSStreamAdapter::Cleanup() { | |
656 if (state_ != SSL_ERROR) { | |
657 state_ = SSL_CLOSED; | |
658 } | |
659 | |
660 if (ssl_fd_) { | |
661 PR_Close(ssl_fd_); | |
662 ssl_fd_ = NULL; | |
663 } | |
664 | |
665 identity_.reset(); | |
666 peer_certificate_.reset(); | |
667 | |
668 Thread::Current()->Clear(this, MSG_DTLS_TIMEOUT); | |
669 } | |
670 | |
671 bool NSSStreamAdapter::GetDigestLength(const std::string& algorithm, | |
672 size_t* length) { | |
673 return NSSCertificate::GetDigestLength(algorithm, length); | |
674 } | |
675 | |
676 StreamResult NSSStreamAdapter::Read(void* data, size_t data_len, | |
677 size_t* read, int* error) { | |
678 // SSL_CONNECTED sanity check. | |
679 switch (state_) { | |
680 case SSL_NONE: | |
681 case SSL_WAIT: | |
682 case SSL_CONNECTING: | |
683 return SR_BLOCK; | |
684 | |
685 case SSL_CONNECTED: | |
686 break; | |
687 | |
688 case SSL_CLOSED: | |
689 return SR_EOS; | |
690 | |
691 case SSL_ERROR: | |
692 default: | |
693 if (error) | |
694 *error = ssl_error_code_; | |
695 return SR_ERROR; | |
696 } | |
697 | |
698 PRInt32 rv = PR_Read(ssl_fd_, data, checked_cast<PRInt32>(data_len)); | |
699 | |
700 if (rv == 0) { | |
701 return SR_EOS; | |
702 } | |
703 | |
704 // Error | |
705 if (rv < 0) { | |
706 PRInt32 err = PR_GetError(); | |
707 | |
708 switch (err) { | |
709 case PR_WOULD_BLOCK_ERROR: | |
710 return SR_BLOCK; | |
711 default: | |
712 Error("Read", -1, false); | |
713 *error = err; // libjingle semantics are that this is impl-specific | |
714 return SR_ERROR; | |
715 } | |
716 } | |
717 | |
718 // Success | |
719 *read = rv; | |
720 | |
721 return SR_SUCCESS; | |
722 } | |
723 | |
724 StreamResult NSSStreamAdapter::Write(const void* data, size_t data_len, | |
725 size_t* written, int* error) { | |
726 // SSL_CONNECTED sanity check. | |
727 switch (state_) { | |
728 case SSL_NONE: | |
729 case SSL_WAIT: | |
730 case SSL_CONNECTING: | |
731 return SR_BLOCK; | |
732 | |
733 case SSL_CONNECTED: | |
734 break; | |
735 | |
736 case SSL_ERROR: | |
737 case SSL_CLOSED: | |
738 default: | |
739 if (error) | |
740 *error = ssl_error_code_; | |
741 return SR_ERROR; | |
742 } | |
743 | |
744 PRInt32 rv = PR_Write(ssl_fd_, data, checked_cast<PRInt32>(data_len)); | |
745 | |
746 // Error | |
747 if (rv < 0) { | |
748 PRInt32 err = PR_GetError(); | |
749 | |
750 switch (err) { | |
751 case PR_WOULD_BLOCK_ERROR: | |
752 return SR_BLOCK; | |
753 default: | |
754 Error("Write", -1, false); | |
755 *error = err; // libjingle semantics are that this is impl-specific | |
756 return SR_ERROR; | |
757 } | |
758 } | |
759 | |
760 // Success | |
761 *written = rv; | |
762 | |
763 return SR_SUCCESS; | |
764 } | |
765 | |
766 void NSSStreamAdapter::OnEvent(StreamInterface* stream, int events, | |
767 int err) { | |
768 int events_to_signal = 0; | |
769 int signal_error = 0; | |
770 ASSERT(stream == this->stream()); | |
771 if ((events & SE_OPEN)) { | |
772 LOG(LS_INFO) << "NSSStreamAdapter::OnEvent SE_OPEN"; | |
773 if (state_ != SSL_WAIT) { | |
774 ASSERT(state_ == SSL_NONE); | |
775 events_to_signal |= SE_OPEN; | |
776 } else { | |
777 state_ = SSL_CONNECTING; | |
778 if (int err = BeginSSL()) { | |
779 Error("BeginSSL", err, true); | |
780 return; | |
781 } | |
782 } | |
783 } | |
784 if ((events & (SE_READ|SE_WRITE))) { | |
785 LOG(LS_INFO) << "NSSStreamAdapter::OnEvent" | |
786 << ((events & SE_READ) ? " SE_READ" : "") | |
787 << ((events & SE_WRITE) ? " SE_WRITE" : ""); | |
788 if (state_ == SSL_NONE) { | |
789 events_to_signal |= events & (SE_READ|SE_WRITE); | |
790 } else if (state_ == SSL_CONNECTING) { | |
791 if (int err = ContinueSSL()) { | |
792 Error("ContinueSSL", err, true); | |
793 return; | |
794 } | |
795 } else if (state_ == SSL_CONNECTED) { | |
796 if (events & SE_WRITE) { | |
797 LOG(LS_INFO) << " -- onStreamWriteable"; | |
798 events_to_signal |= SE_WRITE; | |
799 } | |
800 if (events & SE_READ) { | |
801 LOG(LS_INFO) << " -- onStreamReadable"; | |
802 events_to_signal |= SE_READ; | |
803 } | |
804 } | |
805 } | |
806 if ((events & SE_CLOSE)) { | |
807 LOG(LS_INFO) << "NSSStreamAdapter::OnEvent(SE_CLOSE, " << err << ")"; | |
808 Cleanup(); | |
809 events_to_signal |= SE_CLOSE; | |
810 // SE_CLOSE is the only event that uses the final parameter to OnEvent(). | |
811 ASSERT(signal_error == 0); | |
812 signal_error = err; | |
813 } | |
814 if (events_to_signal) | |
815 StreamAdapterInterface::OnEvent(stream, events_to_signal, signal_error); | |
816 } | |
817 | |
818 void NSSStreamAdapter::OnMessage(Message* msg) { | |
819 // Process our own messages and then pass others to the superclass | |
820 if (MSG_DTLS_TIMEOUT == msg->message_id) { | |
821 LOG(LS_INFO) << "DTLS timeout expired"; | |
822 ContinueSSL(); | |
823 } else { | |
824 StreamInterface::OnMessage(msg); | |
825 } | |
826 } | |
827 | |
828 // Certificate verification callback. Called to check any certificate | |
829 SECStatus NSSStreamAdapter::AuthCertificateHook(void *arg, | |
830 PRFileDesc *fd, | |
831 PRBool checksig, | |
832 PRBool isServer) { | |
833 LOG(LS_INFO) << "NSSStreamAdapter::AuthCertificateHook"; | |
834 // SSL_PeerCertificate returns a pointer that is owned by the caller, and | |
835 // the NSSCertificate constructor copies its argument, so |raw_peer_cert| | |
836 // must be destroyed in this function. | |
837 CERTCertificate* raw_peer_cert = SSL_PeerCertificate(fd); | |
838 NSSCertificate peer_cert(raw_peer_cert); | |
839 CERT_DestroyCertificate(raw_peer_cert); | |
840 | |
841 NSSStreamAdapter *stream = reinterpret_cast<NSSStreamAdapter *>(arg); | |
842 stream->cert_ok_ = false; | |
843 | |
844 // Read the peer's certificate chain. | |
845 CERTCertList* cert_list = SSL_PeerCertificateChain(fd); | |
846 ASSERT(cert_list != NULL); | |
847 | |
848 // If the peer provided multiple certificates, check that they form a valid | |
849 // chain as defined by RFC 5246 Section 7.4.2: "Each following certificate | |
850 // MUST directly certify the one preceding it.". This check does NOT | |
851 // verify other requirements, such as whether the chain reaches a trusted | |
852 // root, self-signed certificates have valid signatures, certificates are not | |
853 // expired, etc. | |
854 // Even if the chain is valid, the leaf certificate must still match a | |
855 // provided certificate or digest. | |
856 if (!NSSCertificate::IsValidChain(cert_list)) { | |
857 CERT_DestroyCertList(cert_list); | |
858 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
859 return SECFailure; | |
860 } | |
861 | |
862 if (stream->peer_certificate_.get()) { | |
863 LOG(LS_INFO) << "Checking against specified certificate"; | |
864 | |
865 // The peer certificate was specified | |
866 if (reinterpret_cast<NSSCertificate *>(stream->peer_certificate_.get())-> | |
867 Equals(&peer_cert)) { | |
868 LOG(LS_INFO) << "Accepted peer certificate"; | |
869 stream->cert_ok_ = true; | |
870 } | |
871 } else if (!stream->peer_certificate_digest_algorithm_.empty()) { | |
872 LOG(LS_INFO) << "Checking against specified digest"; | |
873 // The peer certificate digest was specified | |
874 unsigned char digest[64]; // Maximum size | |
875 size_t digest_length; | |
876 | |
877 if (!peer_cert.ComputeDigest( | |
878 stream->peer_certificate_digest_algorithm_, | |
879 digest, sizeof(digest), &digest_length)) { | |
880 LOG(LS_ERROR) << "Digest computation failed"; | |
881 } else { | |
882 Buffer computed_digest(digest, digest_length); | |
883 if (computed_digest == stream->peer_certificate_digest_value_) { | |
884 LOG(LS_INFO) << "Accepted peer certificate"; | |
885 stream->cert_ok_ = true; | |
886 } | |
887 } | |
888 } else { | |
889 // Other modes, but we haven't implemented yet | |
890 // TODO(ekr@rtfm.com): Implement real certificate validation | |
891 UNIMPLEMENTED; | |
892 } | |
893 | |
894 if (!stream->cert_ok_ && stream->ignore_bad_cert()) { | |
895 LOG(LS_WARNING) << "Ignoring cert error while verifying cert chain"; | |
896 stream->cert_ok_ = true; | |
897 } | |
898 | |
899 if (stream->cert_ok_) | |
900 stream->peer_certificate_.reset(new NSSCertificate(cert_list)); | |
901 | |
902 CERT_DestroyCertList(cert_list); | |
903 | |
904 if (stream->cert_ok_) | |
905 return SECSuccess; | |
906 | |
907 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); | |
908 return SECFailure; | |
909 } | |
910 | |
911 | |
912 SECStatus NSSStreamAdapter::GetClientAuthDataHook(void *arg, PRFileDesc *fd, | |
913 CERTDistNames *caNames, | |
914 CERTCertificate **pRetCert, | |
915 SECKEYPrivateKey **pRetKey) { | |
916 LOG(LS_INFO) << "Client cert requested"; | |
917 NSSStreamAdapter *stream = reinterpret_cast<NSSStreamAdapter *>(arg); | |
918 | |
919 if (!stream->identity_.get()) { | |
920 LOG(LS_ERROR) << "No identity available"; | |
921 return SECFailure; | |
922 } | |
923 | |
924 NSSIdentity *identity = static_cast<NSSIdentity *>(stream->identity_.get()); | |
925 // Destroyed internally by NSS | |
926 *pRetCert = CERT_DupCertificate(identity->certificate().certificate()); | |
927 *pRetKey = SECKEY_CopyPrivateKey(identity->keypair()->privkey()); | |
928 | |
929 return SECSuccess; | |
930 } | |
931 | |
932 bool NSSStreamAdapter::GetSslCipher(std::string* cipher) { | |
933 ASSERT(state_ == SSL_CONNECTED); | |
934 if (state_ != SSL_CONNECTED) | |
935 return false; | |
936 | |
937 SSLChannelInfo channel_info; | |
938 SECStatus rv = SSL_GetChannelInfo(ssl_fd_, &channel_info, | |
939 sizeof(channel_info)); | |
940 if (rv == SECFailure) | |
941 return false; | |
942 | |
943 SSLCipherSuiteInfo ciphersuite_info; | |
944 rv = SSL_GetCipherSuiteInfo(channel_info.cipherSuite, &ciphersuite_info, | |
945 sizeof(ciphersuite_info)); | |
946 if (rv == SECFailure) | |
947 return false; | |
948 | |
949 *cipher = ciphersuite_info.cipherSuiteName; | |
950 return true; | |
951 } | |
952 | |
953 // RFC 5705 Key Exporter | |
954 bool NSSStreamAdapter::ExportKeyingMaterial(const std::string& label, | |
955 const uint8* context, | |
956 size_t context_len, | |
957 bool use_context, | |
958 uint8* result, | |
959 size_t result_len) { | |
960 SECStatus rv = SSL_ExportKeyingMaterial( | |
961 ssl_fd_, | |
962 label.c_str(), | |
963 checked_cast<unsigned int>(label.size()), | |
964 use_context, | |
965 context, | |
966 checked_cast<unsigned int>(context_len), | |
967 result, | |
968 checked_cast<unsigned int>(result_len)); | |
969 | |
970 return rv == SECSuccess; | |
971 } | |
972 | |
973 bool NSSStreamAdapter::SetDtlsSrtpCiphers( | |
974 const std::vector<std::string>& ciphers) { | |
975 #ifdef HAVE_DTLS_SRTP | |
976 std::vector<PRUint16> internal_ciphers; | |
977 if (state_ != SSL_NONE) | |
978 return false; | |
979 | |
980 for (std::vector<std::string>::const_iterator cipher = ciphers.begin(); | |
981 cipher != ciphers.end(); ++cipher) { | |
982 bool found = false; | |
983 for (const SrtpCipherMapEntry *entry = kSrtpCipherMap; entry->cipher_id; | |
984 ++entry) { | |
985 if (*cipher == entry->external_name) { | |
986 found = true; | |
987 internal_ciphers.push_back(entry->cipher_id); | |
988 break; | |
989 } | |
990 } | |
991 | |
992 if (!found) { | |
993 LOG(LS_ERROR) << "Could not find cipher: " << *cipher; | |
994 return false; | |
995 } | |
996 } | |
997 | |
998 if (internal_ciphers.empty()) | |
999 return false; | |
1000 | |
1001 srtp_ciphers_ = internal_ciphers; | |
1002 | |
1003 return true; | |
1004 #else | |
1005 return false; | |
1006 #endif | |
1007 } | |
1008 | |
1009 bool NSSStreamAdapter::GetDtlsSrtpCipher(std::string* cipher) { | |
1010 #ifdef HAVE_DTLS_SRTP | |
1011 ASSERT(state_ == SSL_CONNECTED); | |
1012 if (state_ != SSL_CONNECTED) | |
1013 return false; | |
1014 | |
1015 PRUint16 selected_cipher; | |
1016 | |
1017 SECStatus rv = SSL_GetSRTPCipher(ssl_fd_, &selected_cipher); | |
1018 if (rv == SECFailure) | |
1019 return false; | |
1020 | |
1021 for (const SrtpCipherMapEntry *entry = kSrtpCipherMap; | |
1022 entry->cipher_id; ++entry) { | |
1023 if (selected_cipher == entry->cipher_id) { | |
1024 *cipher = entry->external_name; | |
1025 return true; | |
1026 } | |
1027 } | |
1028 | |
1029 ASSERT(false); // This should never happen | |
1030 #endif | |
1031 return false; | |
1032 } | |
1033 | |
1034 | |
1035 GlobalLockPod NSSContext::lock; | |
1036 NSSContext *NSSContext::global_nss_context; | |
1037 | |
1038 // Static initialization and shutdown | |
1039 NSSContext *NSSContext::Instance() { | |
1040 lock.Lock(); | |
1041 if (!global_nss_context) { | |
1042 scoped_ptr<NSSContext> new_ctx(new NSSContext(PK11_GetInternalSlot())); | |
1043 if (new_ctx->slot_) | |
1044 global_nss_context = new_ctx.release(); | |
1045 } | |
1046 lock.Unlock(); | |
1047 | |
1048 return global_nss_context; | |
1049 } | |
1050 | |
1051 bool NSSContext::InitializeSSL(VerificationCallback callback) { | |
1052 ASSERT(!callback); | |
1053 | |
1054 static bool initialized = false; | |
1055 | |
1056 if (!initialized) { | |
1057 SECStatus rv; | |
1058 | |
1059 rv = NSS_NoDB_Init(NULL); | |
1060 if (rv != SECSuccess) { | |
1061 LOG(LS_ERROR) << "Couldn't initialize NSS error=" << | |
1062 PORT_GetError(); | |
1063 return false; | |
1064 } | |
1065 | |
1066 NSS_SetDomesticPolicy(); | |
1067 | |
1068 initialized = true; | |
1069 } | |
1070 | |
1071 return true; | |
1072 } | |
1073 | |
1074 bool NSSContext::InitializeSSLThread() { | |
1075 // Not needed | |
1076 return true; | |
1077 } | |
1078 | |
1079 bool NSSContext::CleanupSSL() { | |
1080 // Not needed | |
1081 return true; | |
1082 } | |
1083 | |
1084 bool NSSStreamAdapter::HaveDtls() { | |
1085 return true; | |
1086 } | |
1087 | |
1088 bool NSSStreamAdapter::HaveDtlsSrtp() { | |
1089 #ifdef HAVE_DTLS_SRTP | |
1090 return true; | |
1091 #else | |
1092 return false; | |
1093 #endif | |
1094 } | |
1095 | |
1096 bool NSSStreamAdapter::HaveExporter() { | |
1097 return true; | |
1098 } | |
1099 | |
1100 std::string NSSStreamAdapter::GetDefaultSslCipher(SSLProtocolVersion version, | |
1101 KeyType key_type) { | |
1102 if (key_type == KT_RSA) { | |
1103 switch (version) { | |
1104 case SSL_PROTOCOL_TLS_10: | |
1105 case SSL_PROTOCOL_TLS_11: | |
1106 return kDefaultSslCipher10; | |
1107 case SSL_PROTOCOL_TLS_12: | |
1108 default: | |
1109 return kDefaultSslCipher12; | |
1110 } | |
1111 } else if (key_type == KT_ECDSA) { | |
1112 switch (version) { | |
1113 case SSL_PROTOCOL_TLS_10: | |
1114 case SSL_PROTOCOL_TLS_11: | |
1115 return kDefaultSslEcCipher10; | |
1116 case SSL_PROTOCOL_TLS_12: | |
1117 default: | |
1118 return kDefaultSslEcCipher12; | |
1119 } | |
1120 } else { | |
1121 return std::string(); | |
1122 } | |
1123 } | |
1124 | |
1125 } // namespace rtc | |
1126 | |
1127 #endif // HAVE_NSS_SSL_H | |
OLD | NEW |