| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 // Generate a key pair. Caller is responsible for freeing the returned object. | 39 // Generate a key pair. Caller is responsible for freeing the returned object. |
| 40 static EVP_PKEY* MakeKey(const KeyParams& key_params) { | 40 static EVP_PKEY* MakeKey(const KeyParams& key_params) { |
| 41 LOG(LS_INFO) << "Making key pair"; | 41 LOG(LS_INFO) << "Making key pair"; |
| 42 EVP_PKEY* pkey = EVP_PKEY_new(); | 42 EVP_PKEY* pkey = EVP_PKEY_new(); |
| 43 if (key_params.type() == KT_RSA) { | 43 if (key_params.type() == KT_RSA) { |
| 44 int key_length = key_params.rsa_params().mod_size; | 44 int key_length = key_params.rsa_params().mod_size; |
| 45 BIGNUM* exponent = BN_new(); | 45 BIGNUM* exponent = BN_new(); |
| 46 RSA* rsa = RSA_new(); | 46 RSA* rsa = RSA_new(); |
| 47 if (!pkey || !exponent || !rsa || | 47 if (!pkey || !exponent || !rsa || |
| 48 !BN_set_word(exponent, key_params.rsa_params().pub_exp) || | 48 !BN_set_word(exponent, key_params.rsa_params().pub_exp) || |
| 49 !RSA_generate_key_ex(rsa, key_length, exponent, NULL) || | 49 !RSA_generate_key_ex(rsa, key_length, exponent, nullptr) || |
| 50 !EVP_PKEY_assign_RSA(pkey, rsa)) { | 50 !EVP_PKEY_assign_RSA(pkey, rsa)) { |
| 51 EVP_PKEY_free(pkey); | 51 EVP_PKEY_free(pkey); |
| 52 BN_free(exponent); | 52 BN_free(exponent); |
| 53 RSA_free(rsa); | 53 RSA_free(rsa); |
| 54 LOG(LS_ERROR) << "Failed to make RSA key pair"; | 54 LOG(LS_ERROR) << "Failed to make RSA key pair"; |
| 55 return NULL; | 55 return nullptr; |
| 56 } | 56 } |
| 57 // ownership of rsa struct was assigned, don't free it. | 57 // ownership of rsa struct was assigned, don't free it. |
| 58 BN_free(exponent); | 58 BN_free(exponent); |
| 59 } else if (key_params.type() == KT_ECDSA) { | 59 } else if (key_params.type() == KT_ECDSA) { |
| 60 if (key_params.ec_curve() == EC_NIST_P256) { | 60 if (key_params.ec_curve() == EC_NIST_P256) { |
| 61 EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); | 61 EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); |
| 62 | 62 |
| 63 // Ensure curve name is included when EC key is serialized. | 63 // Ensure curve name is included when EC key is serialized. |
| 64 // Without this call, OpenSSL versions before 1.1.0 will create | 64 // Without this call, OpenSSL versions before 1.1.0 will create |
| 65 // certificates that don't work for TLS. | 65 // certificates that don't work for TLS. |
| 66 // This is a no-op for BoringSSL and OpenSSL 1.1.0+ | 66 // This is a no-op for BoringSSL and OpenSSL 1.1.0+ |
| 67 EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE); | 67 EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE); |
| 68 | 68 |
| 69 if (!pkey || !ec_key || !EC_KEY_generate_key(ec_key) || | 69 if (!pkey || !ec_key || !EC_KEY_generate_key(ec_key) || |
| 70 !EVP_PKEY_assign_EC_KEY(pkey, ec_key)) { | 70 !EVP_PKEY_assign_EC_KEY(pkey, ec_key)) { |
| 71 EVP_PKEY_free(pkey); | 71 EVP_PKEY_free(pkey); |
| 72 EC_KEY_free(ec_key); | 72 EC_KEY_free(ec_key); |
| 73 LOG(LS_ERROR) << "Failed to make EC key pair"; | 73 LOG(LS_ERROR) << "Failed to make EC key pair"; |
| 74 return NULL; | 74 return nullptr; |
| 75 } | 75 } |
| 76 // ownership of ec_key struct was assigned, don't free it. | 76 // ownership of ec_key struct was assigned, don't free it. |
| 77 } else { | 77 } else { |
| 78 // Add generation of any other curves here. | 78 // Add generation of any other curves here. |
| 79 EVP_PKEY_free(pkey); | 79 EVP_PKEY_free(pkey); |
| 80 LOG(LS_ERROR) << "ECDSA key requested for unknown curve"; | 80 LOG(LS_ERROR) << "ECDSA key requested for unknown curve"; |
| 81 return NULL; | 81 return nullptr; |
| 82 } | 82 } |
| 83 } else { | 83 } else { |
| 84 EVP_PKEY_free(pkey); | 84 EVP_PKEY_free(pkey); |
| 85 LOG(LS_ERROR) << "Key type requested not understood"; | 85 LOG(LS_ERROR) << "Key type requested not understood"; |
| 86 return NULL; | 86 return nullptr; |
| 87 } | 87 } |
| 88 | 88 |
| 89 LOG(LS_INFO) << "Returning key pair"; | 89 LOG(LS_INFO) << "Returning key pair"; |
| 90 return pkey; | 90 return pkey; |
| 91 } | 91 } |
| 92 | 92 |
| 93 // Generate a self-signed certificate, with the public key from the | 93 // Generate a self-signed certificate, with the public key from the |
| 94 // given key pair. Caller is responsible for freeing the returned object. | 94 // given key pair. Caller is responsible for freeing the returned object. |
| 95 static X509* MakeCertificate(EVP_PKEY* pkey, const SSLIdentityParams& params) { | 95 static X509* MakeCertificate(EVP_PKEY* pkey, const SSLIdentityParams& params) { |
| 96 LOG(LS_INFO) << "Making certificate for " << params.common_name; | 96 LOG(LS_INFO) << "Making certificate for " << params.common_name; |
| 97 X509* x509 = NULL; | 97 X509* x509 = nullptr; |
| 98 BIGNUM* serial_number = NULL; | 98 BIGNUM* serial_number = nullptr; |
| 99 X509_NAME* name = NULL; | 99 X509_NAME* name = nullptr; |
| 100 time_t epoch_off = 0; // Time offset since epoch. | 100 time_t epoch_off = 0; // Time offset since epoch. |
| 101 | 101 |
| 102 if ((x509=X509_new()) == NULL) | 102 if ((x509 = X509_new()) == nullptr) |
| 103 goto error; | 103 goto error; |
| 104 | 104 |
| 105 if (!X509_set_pubkey(x509, pkey)) | 105 if (!X509_set_pubkey(x509, pkey)) |
| 106 goto error; | 106 goto error; |
| 107 | 107 |
| 108 // serial number | 108 // serial number |
| 109 // temporary reference to serial number inside x509 struct | 109 // temporary reference to serial number inside x509 struct |
| 110 ASN1_INTEGER* asn1_serial_number; | 110 ASN1_INTEGER* asn1_serial_number; |
| 111 if ((serial_number = BN_new()) == NULL || | 111 if ((serial_number = BN_new()) == nullptr || |
| 112 !BN_pseudo_rand(serial_number, SERIAL_RAND_BITS, 0, 0) || | 112 !BN_pseudo_rand(serial_number, SERIAL_RAND_BITS, 0, 0) || |
| 113 (asn1_serial_number = X509_get_serialNumber(x509)) == NULL || | 113 (asn1_serial_number = X509_get_serialNumber(x509)) == nullptr || |
| 114 !BN_to_ASN1_INTEGER(serial_number, asn1_serial_number)) | 114 !BN_to_ASN1_INTEGER(serial_number, asn1_serial_number)) |
| 115 goto error; | 115 goto error; |
| 116 | 116 |
| 117 if (!X509_set_version(x509, 2L)) // version 3 | 117 if (!X509_set_version(x509, 2L)) // version 3 |
| 118 goto error; | 118 goto error; |
| 119 | 119 |
| 120 // There are a lot of possible components for the name entries. In | 120 // There are a lot of possible components for the name entries. In |
| 121 // our P2P SSL mode however, the certificates are pre-exchanged | 121 // our P2P SSL mode however, the certificates are pre-exchanged |
| 122 // (through the secure XMPP channel), and so the certificate | 122 // (through the secure XMPP channel), and so the certificate |
| 123 // identification is arbitrary. It can't be empty, so we set some | 123 // identification is arbitrary. It can't be empty, so we set some |
| 124 // arbitrary common_name. Note that this certificate goes out in | 124 // arbitrary common_name. Note that this certificate goes out in |
| 125 // clear during SSL negotiation, so there may be a privacy issue in | 125 // clear during SSL negotiation, so there may be a privacy issue in |
| 126 // putting anything recognizable here. | 126 // putting anything recognizable here. |
| 127 if ((name = X509_NAME_new()) == NULL || | 127 if ((name = X509_NAME_new()) == nullptr || |
| 128 !X509_NAME_add_entry_by_NID( | 128 !X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_UTF8, |
| 129 name, NID_commonName, MBSTRING_UTF8, | 129 (unsigned char*)params.common_name.c_str(), |
| 130 (unsigned char*)params.common_name.c_str(), -1, -1, 0) || | 130 -1, -1, 0) || |
| 131 !X509_set_subject_name(x509, name) || | 131 !X509_set_subject_name(x509, name) || !X509_set_issuer_name(x509, name)) |
| 132 !X509_set_issuer_name(x509, name)) | |
| 133 goto error; | 132 goto error; |
| 134 | 133 |
| 135 if (!X509_time_adj(X509_get_notBefore(x509), params.not_before, &epoch_off) || | 134 if (!X509_time_adj(X509_get_notBefore(x509), params.not_before, &epoch_off) || |
| 136 !X509_time_adj(X509_get_notAfter(x509), params.not_after, &epoch_off)) | 135 !X509_time_adj(X509_get_notAfter(x509), params.not_after, &epoch_off)) |
| 137 goto error; | 136 goto error; |
| 138 | 137 |
| 139 if (!X509_sign(x509, pkey, EVP_sha256())) | 138 if (!X509_sign(x509, pkey, EVP_sha256())) |
| 140 goto error; | 139 goto error; |
| 141 | 140 |
| 142 BN_free(serial_number); | 141 BN_free(serial_number); |
| 143 X509_NAME_free(name); | 142 X509_NAME_free(name); |
| 144 LOG(LS_INFO) << "Returning certificate"; | 143 LOG(LS_INFO) << "Returning certificate"; |
| 145 return x509; | 144 return x509; |
| 146 | 145 |
| 147 error: | 146 error: |
| 148 BN_free(serial_number); | 147 BN_free(serial_number); |
| 149 X509_NAME_free(name); | 148 X509_NAME_free(name); |
| 150 X509_free(x509); | 149 X509_free(x509); |
| 151 return NULL; | 150 return nullptr; |
| 152 } | 151 } |
| 153 | 152 |
| 154 // This dumps the SSL error stack to the log. | 153 // This dumps the SSL error stack to the log. |
| 155 static void LogSSLErrors(const std::string& prefix) { | 154 static void LogSSLErrors(const std::string& prefix) { |
| 156 char error_buf[200]; | 155 char error_buf[200]; |
| 157 unsigned long err; | 156 unsigned long err; |
| 158 | 157 |
| 159 while ((err = ERR_get_error()) != 0) { | 158 while ((err = ERR_get_error()) != 0) { |
| 160 ERR_error_string_n(err, error_buf, sizeof(error_buf)); | 159 ERR_error_string_n(err, error_buf, sizeof(error_buf)); |
| 161 LOG(LS_ERROR) << prefix << ": " << error_buf << "\n"; | 160 LOG(LS_ERROR) << prefix << ": " << error_buf << "\n"; |
| 162 } | 161 } |
| 163 } | 162 } |
| 164 | 163 |
| 165 OpenSSLKeyPair* OpenSSLKeyPair::Generate(const KeyParams& key_params) { | 164 OpenSSLKeyPair* OpenSSLKeyPair::Generate(const KeyParams& key_params) { |
| 166 EVP_PKEY* pkey = MakeKey(key_params); | 165 EVP_PKEY* pkey = MakeKey(key_params); |
| 167 if (!pkey) { | 166 if (!pkey) { |
| 168 LogSSLErrors("Generating key pair"); | 167 LogSSLErrors("Generating key pair"); |
| 169 return NULL; | 168 return nullptr; |
| 170 } | 169 } |
| 171 return new OpenSSLKeyPair(pkey); | 170 return new OpenSSLKeyPair(pkey); |
| 172 } | 171 } |
| 173 | 172 |
| 174 OpenSSLKeyPair* OpenSSLKeyPair::FromPrivateKeyPEMString( | 173 OpenSSLKeyPair* OpenSSLKeyPair::FromPrivateKeyPEMString( |
| 175 const std::string& pem_string) { | 174 const std::string& pem_string) { |
| 176 BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1); | 175 BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1); |
| 177 if (!bio) { | 176 if (!bio) { |
| 178 LOG(LS_ERROR) << "Failed to create a new BIO buffer."; | 177 LOG(LS_ERROR) << "Failed to create a new BIO buffer."; |
| 179 return nullptr; | 178 return nullptr; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 OpenSSLCertificate* OpenSSLCertificate::Generate( | 281 OpenSSLCertificate* OpenSSLCertificate::Generate( |
| 283 OpenSSLKeyPair* key_pair, const SSLIdentityParams& params) { | 282 OpenSSLKeyPair* key_pair, const SSLIdentityParams& params) { |
| 284 SSLIdentityParams actual_params(params); | 283 SSLIdentityParams actual_params(params); |
| 285 if (actual_params.common_name.empty()) { | 284 if (actual_params.common_name.empty()) { |
| 286 // Use a random string, arbitrarily 8chars long. | 285 // Use a random string, arbitrarily 8chars long. |
| 287 actual_params.common_name = CreateRandomString(8); | 286 actual_params.common_name = CreateRandomString(8); |
| 288 } | 287 } |
| 289 X509* x509 = MakeCertificate(key_pair->pkey(), actual_params); | 288 X509* x509 = MakeCertificate(key_pair->pkey(), actual_params); |
| 290 if (!x509) { | 289 if (!x509) { |
| 291 LogSSLErrors("Generating certificate"); | 290 LogSSLErrors("Generating certificate"); |
| 292 return NULL; | 291 return nullptr; |
| 293 } | 292 } |
| 294 #if !defined(NDEBUG) | 293 #if !defined(NDEBUG) |
| 295 PrintCert(x509); | 294 PrintCert(x509); |
| 296 #endif | 295 #endif |
| 297 OpenSSLCertificate* ret = new OpenSSLCertificate(x509); | 296 OpenSSLCertificate* ret = new OpenSSLCertificate(x509); |
| 298 X509_free(x509); | 297 X509_free(x509); |
| 299 return ret; | 298 return ret; |
| 300 } | 299 } |
| 301 | 300 |
| 302 OpenSSLCertificate* OpenSSLCertificate::FromPEMString( | 301 OpenSSLCertificate* OpenSSLCertificate::FromPEMString( |
| 303 const std::string& pem_string) { | 302 const std::string& pem_string) { |
| 304 BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1); | 303 BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1); |
| 305 if (!bio) | 304 if (!bio) |
| 306 return NULL; | 305 return nullptr; |
| 307 BIO_set_mem_eof_return(bio, 0); | 306 BIO_set_mem_eof_return(bio, 0); |
| 308 X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, const_cast<char*>("\0")); | 307 X509* x509 = |
| 308 PEM_read_bio_X509(bio, nullptr, nullptr, const_cast<char*>("\0")); |
| 309 BIO_free(bio); // Frees the BIO, but not the pointed-to string. | 309 BIO_free(bio); // Frees the BIO, but not the pointed-to string. |
| 310 | 310 |
| 311 if (!x509) | 311 if (!x509) |
| 312 return NULL; | 312 return nullptr; |
| 313 | 313 |
| 314 OpenSSLCertificate* ret = new OpenSSLCertificate(x509); | 314 OpenSSLCertificate* ret = new OpenSSLCertificate(x509); |
| 315 X509_free(x509); | 315 X509_free(x509); |
| 316 return ret; | 316 return ret; |
| 317 } | 317 } |
| 318 | 318 |
| 319 // NOTE: This implementation only functions correctly after InitializeSSL | 319 // NOTE: This implementation only functions correctly after InitializeSSL |
| 320 // and before CleanupSSL. | 320 // and before CleanupSSL. |
| 321 bool OpenSSLCertificate::GetSignatureDigestAlgorithm( | 321 bool OpenSSLCertificate::GetSignatureDigestAlgorithm( |
| 322 std::string* algorithm) const { | 322 std::string* algorithm) const { |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 434 BIO_free(bio); | 434 BIO_free(bio); |
| 435 FATAL() << "unreachable code"; | 435 FATAL() << "unreachable code"; |
| 436 } | 436 } |
| 437 char* data; | 437 char* data; |
| 438 size_t length = BIO_get_mem_data(bio, &data); | 438 size_t length = BIO_get_mem_data(bio, &data); |
| 439 der_buffer->SetData(data, length); | 439 der_buffer->SetData(data, length); |
| 440 BIO_free(bio); | 440 BIO_free(bio); |
| 441 } | 441 } |
| 442 | 442 |
| 443 void OpenSSLCertificate::AddReference() const { | 443 void OpenSSLCertificate::AddReference() const { |
| 444 RTC_DCHECK(x509_ != NULL); | 444 RTC_DCHECK(x509_ != nullptr); |
| 445 #if defined(OPENSSL_IS_BORINGSSL) | 445 #if defined(OPENSSL_IS_BORINGSSL) |
| 446 X509_up_ref(x509_); | 446 X509_up_ref(x509_); |
| 447 #else | 447 #else |
| 448 CRYPTO_add(&x509_->references, 1, CRYPTO_LOCK_X509); | 448 CRYPTO_add(&x509_->references, 1, CRYPTO_LOCK_X509); |
| 449 #endif | 449 #endif |
| 450 } | 450 } |
| 451 | 451 |
| 452 bool OpenSSLCertificate::operator==(const OpenSSLCertificate& other) const { | 452 bool OpenSSLCertificate::operator==(const OpenSSLCertificate& other) const { |
| 453 return X509_cmp(this->x509_, other.x509_) == 0; | 453 return X509_cmp(this->x509_, other.x509_) == 0; |
| 454 } | 454 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 469 } else { | 469 } else { |
| 470 return -1; | 470 return -1; |
| 471 } | 471 } |
| 472 | 472 |
| 473 return ASN1TimeToSec(expire_time->data, expire_time->length, long_format); | 473 return ASN1TimeToSec(expire_time->data, expire_time->length, long_format); |
| 474 } | 474 } |
| 475 | 475 |
| 476 OpenSSLIdentity::OpenSSLIdentity(OpenSSLKeyPair* key_pair, | 476 OpenSSLIdentity::OpenSSLIdentity(OpenSSLKeyPair* key_pair, |
| 477 OpenSSLCertificate* certificate) | 477 OpenSSLCertificate* certificate) |
| 478 : key_pair_(key_pair), certificate_(certificate) { | 478 : key_pair_(key_pair), certificate_(certificate) { |
| 479 RTC_DCHECK(key_pair != NULL); | 479 RTC_DCHECK(key_pair != nullptr); |
| 480 RTC_DCHECK(certificate != NULL); | 480 RTC_DCHECK(certificate != nullptr); |
| 481 } | 481 } |
| 482 | 482 |
| 483 OpenSSLIdentity::~OpenSSLIdentity() = default; | 483 OpenSSLIdentity::~OpenSSLIdentity() = default; |
| 484 | 484 |
| 485 OpenSSLIdentity* OpenSSLIdentity::GenerateInternal( | 485 OpenSSLIdentity* OpenSSLIdentity::GenerateInternal( |
| 486 const SSLIdentityParams& params) { | 486 const SSLIdentityParams& params) { |
| 487 OpenSSLKeyPair* key_pair = OpenSSLKeyPair::Generate(params.key_params); | 487 OpenSSLKeyPair* key_pair = OpenSSLKeyPair::Generate(params.key_params); |
| 488 if (key_pair) { | 488 if (key_pair) { |
| 489 OpenSSLCertificate* certificate = | 489 OpenSSLCertificate* certificate = |
| 490 OpenSSLCertificate::Generate(key_pair, params); | 490 OpenSSLCertificate::Generate(key_pair, params); |
| 491 if (certificate) | 491 if (certificate) |
| 492 return new OpenSSLIdentity(key_pair, certificate); | 492 return new OpenSSLIdentity(key_pair, certificate); |
| 493 delete key_pair; | 493 delete key_pair; |
| 494 } | 494 } |
| 495 LOG(LS_INFO) << "Identity generation failed"; | 495 LOG(LS_INFO) << "Identity generation failed"; |
| 496 return NULL; | 496 return nullptr; |
| 497 } | 497 } |
| 498 | 498 |
| 499 OpenSSLIdentity* OpenSSLIdentity::GenerateWithExpiration( | 499 OpenSSLIdentity* OpenSSLIdentity::GenerateWithExpiration( |
| 500 const std::string& common_name, | 500 const std::string& common_name, |
| 501 const KeyParams& key_params, | 501 const KeyParams& key_params, |
| 502 time_t certificate_lifetime) { | 502 time_t certificate_lifetime) { |
| 503 SSLIdentityParams params; | 503 SSLIdentityParams params; |
| 504 params.key_params = key_params; | 504 params.key_params = key_params; |
| 505 params.common_name = common_name; | 505 params.common_name = common_name; |
| 506 time_t now = time(NULL); | 506 time_t now = time(nullptr); |
| 507 params.not_before = now + kCertificateWindowInSeconds; | 507 params.not_before = now + kCertificateWindowInSeconds; |
| 508 params.not_after = now + certificate_lifetime; | 508 params.not_after = now + certificate_lifetime; |
| 509 if (params.not_before > params.not_after) | 509 if (params.not_before > params.not_after) |
| 510 return nullptr; | 510 return nullptr; |
| 511 return GenerateInternal(params); | 511 return GenerateInternal(params); |
| 512 } | 512 } |
| 513 | 513 |
| 514 OpenSSLIdentity* OpenSSLIdentity::GenerateForTest( | 514 OpenSSLIdentity* OpenSSLIdentity::GenerateForTest( |
| 515 const SSLIdentityParams& params) { | 515 const SSLIdentityParams& params) { |
| 516 return GenerateInternal(params); | 516 return GenerateInternal(params); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 567 bool OpenSSLIdentity::operator==(const OpenSSLIdentity& other) const { | 567 bool OpenSSLIdentity::operator==(const OpenSSLIdentity& other) const { |
| 568 return *this->key_pair_ == *other.key_pair_ && | 568 return *this->key_pair_ == *other.key_pair_ && |
| 569 *this->certificate_ == *other.certificate_; | 569 *this->certificate_ == *other.certificate_; |
| 570 } | 570 } |
| 571 | 571 |
| 572 bool OpenSSLIdentity::operator!=(const OpenSSLIdentity& other) const { | 572 bool OpenSSLIdentity::operator!=(const OpenSSLIdentity& other) const { |
| 573 return !(*this == other); | 573 return !(*this == other); |
| 574 } | 574 } |
| 575 | 575 |
| 576 } // namespace rtc | 576 } // namespace rtc |
| OLD | NEW |