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, |