| Index: chrome/common/extensions/api/networking_private/networking_private_crypto_nss.cc
|
| diff --git a/chrome/common/extensions/api/networking_private/networking_private_crypto_nss.cc b/chrome/common/extensions/api/networking_private/networking_private_crypto_nss.cc
|
| index 08397627d4ceeb2d9d1fee63be2606998f6b70aa..2cdc33b68a0abca49eef4af2424e79c5e781c830 100644
|
| --- a/chrome/common/extensions/api/networking_private/networking_private_crypto_nss.cc
|
| +++ b/chrome/common/extensions/api/networking_private/networking_private_crypto_nss.cc
|
| @@ -45,6 +45,94 @@
|
| } // namespace
|
|
|
| namespace networking_private_crypto {
|
| +
|
| +bool VerifyCredentials(const std::string& certificate,
|
| + const std::string& signature,
|
| + const std::string& data,
|
| + const std::string& connected_mac) {
|
| + crypto::EnsureNSSInit();
|
| +
|
| + std::vector<uint8_t> cert_data;
|
| + if (!GetDERFromPEM(certificate, "CERTIFICATE", &cert_data)) {
|
| + LOG(ERROR) << "Failed to parse certificate.";
|
| + return false;
|
| + }
|
| + SECItem der_cert;
|
| + der_cert.type = siDERCertBuffer;
|
| + der_cert.data = cert_data.data();
|
| + der_cert.len = cert_data.size();
|
| +
|
| + // Parse into a certificate structure.
|
| + typedef scoped_ptr<
|
| + CERTCertificate,
|
| + crypto::NSSDestroyer<CERTCertificate, CERT_DestroyCertificate> >
|
| + ScopedCERTCertificate;
|
| + ScopedCERTCertificate cert(CERT_NewTempCertificate(
|
| + CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE));
|
| + if (!cert.get()) {
|
| + LOG(ERROR) << "Failed to parse certificate.";
|
| + return false;
|
| + }
|
| +
|
| + // Check that the certificate is signed by trusted CA.
|
| + SECItem trusted_ca_key_der_item;
|
| + trusted_ca_key_der_item.type = siDERCertBuffer;
|
| + trusted_ca_key_der_item.data =
|
| + const_cast<unsigned char*>(kTrustedCAPublicKeyDER);
|
| + trusted_ca_key_der_item.len = kTrustedCAPublicKeyDERLength;
|
| + crypto::ScopedSECKEYPublicKey ca_public_key(
|
| + SECKEY_ImportDERPublicKey(&trusted_ca_key_der_item, CKK_RSA));
|
| + SECStatus verified = CERT_VerifySignedDataWithPublicKey(
|
| + &cert->signatureWrap, ca_public_key.get(), NULL);
|
| + if (verified != SECSuccess) {
|
| + LOG(ERROR) << "Certificate is not issued by the trusted CA.";
|
| + return false;
|
| + }
|
| +
|
| + // Check that the device listed in the certificate is correct.
|
| + // Something like evt_e161 001a11ffacdf
|
| + char* common_name = CERT_GetCommonName(&cert->subject);
|
| + if (!common_name) {
|
| + LOG(ERROR) << "Certificate does not have common name.";
|
| + return false;
|
| + }
|
| +
|
| + std::string subject_name(common_name);
|
| + PORT_Free(common_name);
|
| + std::string translated_mac;
|
| + base::RemoveChars(connected_mac, ":", &translated_mac);
|
| + if (!EndsWith(subject_name, translated_mac, false)) {
|
| + LOG(ERROR) << "MAC addresses don't match.";
|
| + return false;
|
| + }
|
| +
|
| + // Make sure that the certificate matches the unsigned data presented.
|
| + // Verify that the |signature| matches |data|.
|
| + crypto::ScopedSECKEYPublicKey public_key(CERT_ExtractPublicKey(cert.get()));
|
| + if (!public_key.get()) {
|
| + LOG(ERROR) << "Unable to extract public key from certificate.";
|
| + return false;
|
| + }
|
| + SECItem signature_item;
|
| + signature_item.type = siBuffer;
|
| + signature_item.data =
|
| + reinterpret_cast<unsigned char*>(const_cast<char*>(signature.c_str()));
|
| + signature_item.len = static_cast<unsigned int>(signature.size());
|
| + verified = VFY_VerifyDataDirect(
|
| + reinterpret_cast<unsigned char*>(const_cast<char*>(data.c_str())),
|
| + data.size(),
|
| + public_key.get(),
|
| + &signature_item,
|
| + SEC_OID_PKCS1_RSA_ENCRYPTION,
|
| + SEC_OID_SHA1,
|
| + NULL,
|
| + NULL);
|
| + if (verified != SECSuccess) {
|
| + LOG(ERROR) << "Signed blobs did not match.";
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
|
|
| bool EncryptByteString(const std::vector<uint8_t>& pub_key_der,
|
| const std::string& data,
|
|
|