Extension API enterprise.platformKeys.
[chromium-blink-merge.git] / chrome / renderer / resources / extensions / enterprise_platform_keys / subtle_crypto.js
blobd94722c79985f7ac9345f363ce216ce456be922f
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.
5 var utils = require('utils');
6 var internalAPI = require('enterprise.platformKeys.internalAPI');
7 var intersect = require('enterprise.platformKeys.utils').intersect;
8 var KeyPair = require('enterprise.platformKeys.KeyPair').KeyPair;
9 var keyModule = require('enterprise.platformKeys.Key');
10 var getSpki = keyModule.getSpki;
11 var KeyUsage = keyModule.KeyUsage;
13 // This error is thrown by the internal and public API's token functions and
14 // must be rethrown by this custom binding. Keep this in sync with the C++ part
15 // of this API.
16 var errorInvalidToken = "The token is not valid.";
18 // The following errors are specified in WebCrypto.
19 // TODO(pneubeck): These should be DOMExceptions.
20 function CreateNotSupportedError() {
21   return new Error('The algorithm is not supported');
24 function CreateInvalidAccessError() {
25   return new Error('The requested operation is not valid for the provided key');
28 function CreateDataError() {
29   return new Error('Data provided to an operation does not meet requirements');
32 function CreateSyntaxError() {
33   return new Error('A required parameter was missing our out-of-range');
36 function CreateOperationError() {
37   return new Error('The operation failed for an operation-specific reason');
40 // Catches an |internalErrorInvalidToken|. If so, forwards it to |reject| and
41 // returns true.
42 function catchInvalidTokenError(reject) {
43   if (chrome.runtime.lastError &&
44       chrome.runtime.lastError.message == errorInvalidToken) {
45     reject(chrome.runtime.lastError);
46     return true;
47   }
48   return false;
51 /**
52  * Implementation of WebCrypto.SubtleCrypto used in enterprise.platformKeys.
53  * @param {string} tokenId The id of the backing Token.
54  * @constructor
55  */
56 var SubtleCryptoImpl = function(tokenId) {
57   this.tokenId = tokenId;
60 SubtleCryptoImpl.prototype.generateKey =
61     function(algorithm, extractable, keyUsages) {
62   var subtleCrypto = this;
63   return new Promise(function(resolve, reject) {
64     // TODO(pneubeck): Apply the algorithm normalization of the WebCrypto
65     // implementation.
67     if (extractable) {
68       // Note: This deviates from WebCrypto.SubtleCrypto.
69       throw CreateNotSupportedError();
70     }
71     if (intersect(keyUsages, [KeyUsage.sign, KeyUsage.verify]).length !=
72         keyUsages.length) {
73       throw CreateDataError();
74     }
75     if (!algorithm.name) {
76       // TODO(pneubeck): It's not clear from the WebCrypto spec which error to
77       // throw here.
78       throw CreateSyntaxError();
79     }
81     if (algorithm.name.toUpperCase() !== 'RSASSA-PKCS1-V1_5') {
82       // Note: This deviates from WebCrypto.SubtleCrypto.
83       throw CreateNotSupportedError();
84     }
85     if (!algorithm.modulusLength || !algorithm.publicExponent)
86       throw CreateSyntaxError();
88     internalAPI.generateKey(
89         subtleCrypto.tokenId, algorithm.modulusLength, function(spki) {
90           if (catchInvalidTokenError(reject))
91             return;
92           if (chrome.runtime.lastError) {
93             reject(CreateOperationError());
94             return;
95           }
96           resolve(new KeyPair(spki, algorithm, keyUsages));
97         });
98   });
101 SubtleCryptoImpl.prototype.sign = function(algorithm, key, dataView) {
102   var subtleCrypto = this;
103   return new Promise(function(resolve, reject) {
104     if (key.type != 'private' || key.usages.indexOf(KeyUsage.sign) == -1)
105       throw CreateInvalidAccessError();
107     // Create an ArrayBuffer that equals the dataView. Note that dataView.buffer
108     // might contain more data than dataView.
109     var data = dataView.buffer.slice(dataView.byteOffset,
110                                      dataView.byteOffset + dataView.byteLength);
111     internalAPI.sign(
112         subtleCrypto.tokenId, getSpki(key), data, function(signature) {
113           if (catchInvalidTokenError(reject))
114             return;
115           if (chrome.runtime.lastError) {
116             reject(CreateOperationError());
117             return;
118           }
119           resolve(signature);
120         });
121   });
124 SubtleCryptoImpl.prototype.exportKey = function(format, key) {
125   return new Promise(function(resolve, reject) {
126     if (format == 'pkcs8') {
127       // Either key.type is not 'private' or the key is not extractable. In both
128       // cases the error is the same.
129       throw CreateInvalidAccessError();
130     } else if (format == 'spki') {
131       if (key.type != 'public')
132         throw CreateInvalidAccessError();
133       resolve(getSpki(key));
134     } else {
135       // TODO(pneubeck): It should be possible to export to format 'jwk'.
136       throw CreateNotSupportedError();
137     }
138   });
141 exports.SubtleCrypto =
142     utils.expose('SubtleCrypto',
143                  SubtleCryptoImpl,
144                  {functions:['generateKey', 'sign', 'exportKey']});