1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.h" 6 7 #include "base/bind.h" 8 #include "base/values.h" 9 #include "chrome/browser/chromeos/platform_keys/platform_keys.h" 10 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h" 11 #include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h" 12 #include "chrome/common/extensions/api/enterprise_platform_keys.h" 13 #include "chrome/common/extensions/api/enterprise_platform_keys_internal.h" 14 #include "content/public/browser/browser_thread.h" 15 #include "net/cert/x509_certificate.h" 16 17 namespace extensions { 18 19 namespace { 20 21 namespace api_epk = api::enterprise_platform_keys; 22 namespace api_epki = api::enterprise_platform_keys_internal; 23 24 // This error will occur if a token is removed and will be exposed to the 25 // extension. Keep this in sync with the custom binding in Javascript. 26 const char kErrorInvalidToken[] = "The token is not valid."; 27 28 const char kErrorAlgorithmNotSupported[] = "Algorithm not supported."; 29 const char kErrorInvalidX509Cert[] = 30 "Certificate is not a valid X.509 certificate."; 31 const char kTokenIdUser[] = "user"; 32 33 // Returns whether |token_id| references a known Token. 34 bool ValidateToken(const std::string& token_id) { 35 // For now, the user token is the only valid one. 36 return token_id == kTokenIdUser; 37 } 38 39 } // namespace 40 41 EnterprisePlatformKeysInternalGenerateKeyFunction:: 42 ~EnterprisePlatformKeysInternalGenerateKeyFunction() { 43 } 44 45 ExtensionFunction::ResponseAction 46 EnterprisePlatformKeysInternalGenerateKeyFunction::Run() { 47 scoped_ptr<api_epki::GenerateKey::Params> params( 48 api_epki::GenerateKey::Params::Create(*args_)); 49 // TODO(pneubeck): Add support for unsigned integers to IDL. 50 EXTENSION_FUNCTION_VALIDATE(params && params->modulus_length >= 0); 51 if (!ValidateToken(params->token_id)) 52 return RespondNow(Error(kErrorInvalidToken)); 53 54 chromeos::PlatformKeysService* service = 55 chromeos::PlatformKeysServiceFactory::GetForBrowserContext( 56 browser_context()); 57 DCHECK(service); 58 59 service->GenerateRSAKey( 60 params->token_id, 61 params->modulus_length, 62 extension_id(), 63 base::Bind( 64 &EnterprisePlatformKeysInternalGenerateKeyFunction::OnGeneratedKey, 65 this)); 66 return RespondLater(); 67 } 68 69 void EnterprisePlatformKeysInternalGenerateKeyFunction::OnGeneratedKey( 70 const std::string& public_key_der, 71 const std::string& error_message) { 72 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 73 if (error_message.empty()) { 74 Respond( 75 ArgumentList(api_epki::GenerateKey::Results::Create(public_key_der))); 76 } else { 77 Respond(Error(error_message)); 78 } 79 } 80 81 EnterprisePlatformKeysInternalSignFunction:: 82 ~EnterprisePlatformKeysInternalSignFunction() { 83 } 84 85 ExtensionFunction::ResponseAction 86 EnterprisePlatformKeysInternalSignFunction::Run() { 87 scoped_ptr<api_epki::Sign::Params> params( 88 api_epki::Sign::Params::Create(*args_)); 89 EXTENSION_FUNCTION_VALIDATE(params); 90 if (!ValidateToken(params->token_id)) 91 return RespondNow(Error(kErrorInvalidToken)); 92 93 chromeos::platform_keys::HashAlgorithm hash_algorithm; 94 if (params->hash_algorithm_name == "SHA-1") 95 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA1; 96 else if (params->hash_algorithm_name == "SHA-256") 97 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA256; 98 else if (params->hash_algorithm_name == "SHA-384") 99 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA384; 100 else if (params->hash_algorithm_name == "SHA-512") 101 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA512; 102 else 103 return RespondNow(Error(kErrorAlgorithmNotSupported)); 104 105 chromeos::PlatformKeysService* service = 106 chromeos::PlatformKeysServiceFactory::GetForBrowserContext( 107 browser_context()); 108 DCHECK(service); 109 110 service->Sign( 111 params->token_id, 112 params->public_key, 113 hash_algorithm, 114 params->data, 115 extension_id(), 116 base::Bind(&EnterprisePlatformKeysInternalSignFunction::OnSigned, this)); 117 return RespondLater(); 118 } 119 120 void EnterprisePlatformKeysInternalSignFunction::OnSigned( 121 const std::string& signature, 122 const std::string& error_message) { 123 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 124 if (error_message.empty()) 125 Respond(ArgumentList(api_epki::Sign::Results::Create(signature))); 126 else 127 Respond(Error(error_message)); 128 } 129 130 EnterprisePlatformKeysGetCertificatesFunction:: 131 ~EnterprisePlatformKeysGetCertificatesFunction() { 132 } 133 134 ExtensionFunction::ResponseAction 135 EnterprisePlatformKeysGetCertificatesFunction::Run() { 136 scoped_ptr<api_epk::GetCertificates::Params> params( 137 api_epk::GetCertificates::Params::Create(*args_)); 138 EXTENSION_FUNCTION_VALIDATE(params); 139 if (!ValidateToken(params->token_id)) 140 return RespondNow(Error(kErrorInvalidToken)); 141 142 chromeos::platform_keys::GetCertificates( 143 params->token_id, 144 base::Bind( 145 &EnterprisePlatformKeysGetCertificatesFunction::OnGotCertificates, 146 this), 147 browser_context()); 148 return RespondLater(); 149 } 150 151 void EnterprisePlatformKeysGetCertificatesFunction::OnGotCertificates( 152 scoped_ptr<net::CertificateList> certs, 153 const std::string& error_message) { 154 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 155 if (!error_message.empty()) { 156 Respond(Error(error_message)); 157 return; 158 } 159 160 scoped_ptr<base::ListValue> client_certs(new base::ListValue()); 161 for (net::CertificateList::const_iterator it = certs->begin(); 162 it != certs->end(); 163 ++it) { 164 std::string der_encoding; 165 net::X509Certificate::GetDEREncoded((*it)->os_cert_handle(), &der_encoding); 166 client_certs->Append(base::BinaryValue::CreateWithCopiedBuffer( 167 der_encoding.data(), der_encoding.size())); 168 } 169 170 scoped_ptr<base::ListValue> results(new base::ListValue()); 171 results->Append(client_certs.release()); 172 Respond(ArgumentList(results.Pass())); 173 } 174 175 EnterprisePlatformKeysImportCertificateFunction:: 176 ~EnterprisePlatformKeysImportCertificateFunction() { 177 } 178 179 ExtensionFunction::ResponseAction 180 EnterprisePlatformKeysImportCertificateFunction::Run() { 181 scoped_ptr<api_epk::ImportCertificate::Params> params( 182 api_epk::ImportCertificate::Params::Create(*args_)); 183 EXTENSION_FUNCTION_VALIDATE(params); 184 if (!ValidateToken(params->token_id)) 185 return RespondNow(Error(kErrorInvalidToken)); 186 187 const std::string& cert_der = params->certificate; 188 scoped_refptr<net::X509Certificate> cert_x509 = 189 net::X509Certificate::CreateFromBytes(cert_der.data(), cert_der.size()); 190 if (!cert_x509) 191 return RespondNow(Error(kErrorInvalidX509Cert)); 192 193 chromeos::platform_keys::ImportCertificate( 194 params->token_id, 195 cert_x509, 196 base::Bind(&EnterprisePlatformKeysImportCertificateFunction:: 197 OnImportedCertificate, 198 this), 199 browser_context()); 200 return RespondLater(); 201 } 202 203 void EnterprisePlatformKeysImportCertificateFunction::OnImportedCertificate( 204 const std::string& error_message) { 205 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 206 if (error_message.empty()) 207 Respond(NoArguments()); 208 else 209 Respond(Error(error_message)); 210 } 211 212 EnterprisePlatformKeysRemoveCertificateFunction:: 213 ~EnterprisePlatformKeysRemoveCertificateFunction() { 214 } 215 216 ExtensionFunction::ResponseAction 217 EnterprisePlatformKeysRemoveCertificateFunction::Run() { 218 scoped_ptr<api_epk::RemoveCertificate::Params> params( 219 api_epk::RemoveCertificate::Params::Create(*args_)); 220 EXTENSION_FUNCTION_VALIDATE(params); 221 if (!ValidateToken(params->token_id)) 222 return RespondNow(Error(kErrorInvalidToken)); 223 224 const std::string& cert_der = params->certificate; 225 scoped_refptr<net::X509Certificate> cert_x509 = 226 net::X509Certificate::CreateFromBytes(cert_der.data(), cert_der.size()); 227 if (!cert_x509) 228 return RespondNow(Error(kErrorInvalidX509Cert)); 229 230 chromeos::platform_keys::RemoveCertificate( 231 params->token_id, 232 cert_x509, 233 base::Bind(&EnterprisePlatformKeysRemoveCertificateFunction:: 234 OnRemovedCertificate, 235 this), 236 browser_context()); 237 return RespondLater(); 238 } 239 240 void EnterprisePlatformKeysRemoveCertificateFunction::OnRemovedCertificate( 241 const std::string& error_message) { 242 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 243 if (error_message.empty()) 244 Respond(NoArguments()); 245 else 246 Respond(Error(error_message)); 247 } 248 249 EnterprisePlatformKeysInternalGetTokensFunction:: 250 ~EnterprisePlatformKeysInternalGetTokensFunction() { 251 } 252 253 ExtensionFunction::ResponseAction 254 EnterprisePlatformKeysInternalGetTokensFunction::Run() { 255 EXTENSION_FUNCTION_VALIDATE(args_->empty()); 256 257 std::vector<std::string> token_ids; 258 token_ids.push_back(kTokenIdUser); 259 return RespondNow( 260 ArgumentList(api_epki::GetTokens::Results::Create(token_ids))); 261 } 262 263 } // namespace extensions 264