Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / renderer / resources / extensions / platform_keys / subtle_crypto.js
blob14a5388cef3ad8f189b8b05287e0b8da9c79f6c9
1 // Copyright 2015 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.
5 var utils = require('utils');
6 var internalAPI = require('platformKeys.internalAPI');
7 var keyModule = require('platformKeys.Key');
8 var getSpki = keyModule.getSpki;
9 var KeyUsage = keyModule.KeyUsage;
11 var normalizeAlgorithm =
12     requireNative('platform_keys_natives').NormalizeAlgorithm;
14 // This error is thrown by the internal and public API's token functions and
15 // must be rethrown by this custom binding. Keep this in sync with the C++ part
16 // of this API.
17 var errorInvalidToken = "The token is not valid.";
19 // The following errors are specified in WebCrypto.
20 // TODO(pneubeck): These should be DOMExceptions.
21 function CreateNotSupportedError() {
22   return new Error('The algorithm is not supported');
25 function CreateInvalidAccessError() {
26   return new Error('The requested operation is not valid for the provided key');
29 function CreateDataError() {
30   return new Error('Data provided to an operation does not meet requirements');
33 function CreateSyntaxError() {
34   return new Error('A required parameter was missing or out-of-range');
37 function CreateOperationError() {
38   return new Error('The operation failed for an operation-specific reason');
41 // Catches an |internalErrorInvalidToken|. If so, forwards it to |reject| and
42 // returns true.
43 function catchInvalidTokenError(reject) {
44   if (chrome.runtime.lastError &&
45       chrome.runtime.lastError.message == errorInvalidToken) {
46     reject(chrome.runtime.lastError);
47     return true;
48   }
49   return false;
52 /**
53  * Implementation of WebCrypto.SubtleCrypto used in platformKeys and
54  * enterprise.platformKeys.
55  * @param {string} tokenId The id of the backing Token.
56  * @constructor
57  */
58 var SubtleCryptoImpl = function(tokenId) {
59   this.tokenId = tokenId;
62 SubtleCryptoImpl.prototype.sign = function(algorithm, key, dataView) {
63   var subtleCrypto = this;
64   return new Promise(function(resolve, reject) {
65     if (key.type != 'private' || key.usages.indexOf(KeyUsage.sign) == -1)
66       throw CreateInvalidAccessError();
68     var normalizedAlgorithmParameters =
69         normalizeAlgorithm(algorithm, 'Sign');
70     if (!normalizedAlgorithmParameters) {
71       // TODO(pneubeck): It's not clear from the WebCrypto spec which error to
72       // throw here.
73       throw CreateSyntaxError();
74     }
76     // Create an ArrayBuffer that equals the dataView. Note that dataView.buffer
77     // might contain more data than dataView.
78     var data = dataView.buffer.slice(dataView.byteOffset,
79                                      dataView.byteOffset + dataView.byteLength);
80     internalAPI.sign(subtleCrypto.tokenId,
81                      getSpki(key),
82                      key.algorithm.hash.name,
83                      data,
84                      function(signature) {
85       if (catchInvalidTokenError(reject))
86         return;
87       if (chrome.runtime.lastError) {
88         reject(CreateOperationError());
89         return;
90       }
91       resolve(signature);
92     });
93   });
96 SubtleCryptoImpl.prototype.exportKey = function(format, key) {
97   return new Promise(function(resolve, reject) {
98     if (format == 'pkcs8') {
99       // Either key.type is not 'private' or the key is not extractable. In both
100       // cases the error is the same.
101       throw CreateInvalidAccessError();
102     } else if (format == 'spki') {
103       if (key.type != 'public')
104         throw CreateInvalidAccessError();
105       resolve(getSpki(key));
106     } else {
107       // TODO(pneubeck): It should be possible to export to format 'jwk'.
108       throw CreateNotSupportedError();
109     }
110   });
113 // Required for subclassing.
114 exports.SubtleCryptoImpl = SubtleCryptoImpl
116 exports.SubtleCrypto =
117     utils.expose('SubtleCrypto',
118                  SubtleCryptoImpl,
119                  {functions:['sign', 'exportKey']});