1/* 2 * Copyright 2012 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 "webrtc/p2p/base/transportdescriptionfactory.h" 12 13#include "webrtc/p2p/base/transportdescription.h" 14#include "webrtc/base/helpers.h" 15#include "webrtc/base/logging.h" 16#include "webrtc/base/messagedigest.h" 17#include "webrtc/base/sslfingerprint.h" 18 19namespace cricket { 20 21TransportDescriptionFactory::TransportDescriptionFactory() 22 : secure_(SEC_DISABLED) { 23} 24 25TransportDescription* TransportDescriptionFactory::CreateOffer( 26 const TransportOptions& options, 27 const TransportDescription* current_description) const { 28 rtc::scoped_ptr<TransportDescription> desc(new TransportDescription()); 29 30 // Generate the ICE credentials if we don't already have them. 31 if (!current_description || options.ice_restart) { 32 desc->ice_ufrag = rtc::CreateRandomString(ICE_UFRAG_LENGTH); 33 desc->ice_pwd = rtc::CreateRandomString(ICE_PWD_LENGTH); 34 } else { 35 desc->ice_ufrag = current_description->ice_ufrag; 36 desc->ice_pwd = current_description->ice_pwd; 37 } 38 39 // If we are trying to establish a secure transport, add a fingerprint. 40 if (secure_ == SEC_ENABLED || secure_ == SEC_REQUIRED) { 41 // Fail if we can't create the fingerprint. 42 // If we are the initiator set role to "actpass". 43 if (!SetSecurityInfo(desc.get(), CONNECTIONROLE_ACTPASS)) { 44 return NULL; 45 } 46 } 47 48 return desc.release(); 49} 50 51TransportDescription* TransportDescriptionFactory::CreateAnswer( 52 const TransportDescription* offer, 53 const TransportOptions& options, 54 const TransportDescription* current_description) const { 55 // TODO(juberti): Figure out why we get NULL offers, and fix this upstream. 56 if (!offer) { 57 LOG(LS_WARNING) << "Failed to create TransportDescription answer " << 58 "because offer is NULL"; 59 return NULL; 60 } 61 62 rtc::scoped_ptr<TransportDescription> desc(new TransportDescription()); 63 // Generate the ICE credentials if we don't already have them or ice is 64 // being restarted. 65 if (!current_description || options.ice_restart) { 66 desc->ice_ufrag = rtc::CreateRandomString(ICE_UFRAG_LENGTH); 67 desc->ice_pwd = rtc::CreateRandomString(ICE_PWD_LENGTH); 68 } else { 69 desc->ice_ufrag = current_description->ice_ufrag; 70 desc->ice_pwd = current_description->ice_pwd; 71 } 72 73 // Negotiate security params. 74 if (offer && offer->identity_fingerprint.get()) { 75 // The offer supports DTLS, so answer with DTLS, as long as we support it. 76 if (secure_ == SEC_ENABLED || secure_ == SEC_REQUIRED) { 77 // Fail if we can't create the fingerprint. 78 // Setting DTLS role to active. 79 ConnectionRole role = (options.prefer_passive_role) ? 80 CONNECTIONROLE_PASSIVE : CONNECTIONROLE_ACTIVE; 81 82 if (!SetSecurityInfo(desc.get(), role)) { 83 return NULL; 84 } 85 } 86 } else if (secure_ == SEC_REQUIRED) { 87 // We require DTLS, but the other side didn't offer it. Fail. 88 LOG(LS_WARNING) << "Failed to create TransportDescription answer " 89 "because of incompatible security settings"; 90 return NULL; 91 } 92 93 return desc.release(); 94} 95 96bool TransportDescriptionFactory::SetSecurityInfo( 97 TransportDescription* desc, ConnectionRole role) const { 98 if (!certificate_) { 99 LOG(LS_ERROR) << "Cannot create identity digest with no certificate"; 100 return false; 101 } 102 103 // This digest algorithm is used to produce the a=fingerprint lines in SDP. 104 // RFC 4572 Section 5 requires that those lines use the same hash function as 105 // the certificate's signature. 106 std::string digest_alg; 107 if (!certificate_->ssl_certificate().GetSignatureDigestAlgorithm( 108 &digest_alg)) { 109 LOG(LS_ERROR) << "Failed to retrieve the certificate's digest algorithm"; 110 return false; 111 } 112 113 desc->identity_fingerprint.reset( 114 rtc::SSLFingerprint::Create(digest_alg, certificate_->identity())); 115 if (!desc->identity_fingerprint.get()) { 116 LOG(LS_ERROR) << "Failed to create identity fingerprint, alg=" 117 << digest_alg; 118 return false; 119 } 120 121 // Assign security role. 122 desc->connection_role = role; 123 return true; 124} 125 126} // namespace cricket 127